Integration with Bunny Storage - Review my code

I know this should be simple but its just not working. Any help will be appreciated.
I created bunny.js in content/adapters/storage.
It has the following code:

const BaseAdapter = require('ghost-storage-base');
const fetch = require('node-fetch');

class BunnyAdapter extends BaseAdapter {
  constructor(config) {
    super(config);
    this.config = config;
    this.storageUrl = config.bunny.storageUrl;
    this.accessKey = config.bunny.accessKey;
    this.storageZone = config.bunny.storageZone;
  }

  async exists(fileName) {
    const response = await fetch(`${this.storageUrl}/${this.storageZone}/${fileName}`, {
      method: 'HEAD',
      headers: {
        'AccessKey': this.accessKey
      }
    });
    return response.ok;
  }

  async save(image, targetDir) {
    const response = await fetch(`${this.storageUrl}/${this.storageZone}/${targetDir}/${image.name}`, {
      method: 'PUT',
      headers: {
        'Content-Length': image.size,
        'AccessKey': this.accessKey,
        'Content-Type': image.type
      },
      body: image
    });
    if (!response.ok) {
      throw new Error(`BunnyCDN storage adapter failed to save file ${image.name}`);
    }
    return `${this.config.bunny.cdnUrl}/${this.storageZone}/${targetDir}/${image.name}`;
  }

  async serve(options) {
    return function customServe(req, res, next) {
      next();
    }
  }

  async delete(fileName) {
    const response = await fetch(`${this.storageUrl}/${this.storageZone}/${fileName}`, {
      method: 'DELETE',
      headers: {
        'AccessKey': this.accessKey
      }
    });
    if (!response.ok) {
      throw new Error(`BunnyCDN storage adapter failed to delete file ${fileName}`);
    }
  }

  async read(options) {
    const response = await fetch(`${this.storageUrl}/${this.storageZone}/${options.path}`, {
      method: 'GET',
      headers: {
        'AccessKey': this.accessKey
      }
    });
    if (!response.ok) {
      throw new Error(`BunnyCDN storage adapter failed to read file ${options.path}`);
    }
    return response.text();
  }
}

module.exports = BunnyAdapter;

Then i edit the config.production.json
It looks like this

{
  "url": "https://xxxxx.com",
  "server": {
    "port": 2368,
    "host": "127.0.0.1"
  },
  "database": {
    "client": "mysql",
    "connection": {
      "host": "localhost",
      "user": "ghost-621",
      "password": "Y6})!vARmiCRGY5e)Mq>",
      "port": 3306,
      "database": "ghost_production"
    }
  },
  "mail": {
    "transport": "Direct"
  },
  "logging": {
    "transports": [
      "file",
      "stdout"
    ]
  },
  "process": "systemd",
  "paths": {
    "contentPath": "/var/www/ghost/content",
  }
"storage": {
  "active": "bunny",
  "bunny": {
    "cdnUrl": "web.b-cdn.net",
    "storageUrl": "storage.bunnycdn.com",
    "accessKey": "xxxxxxx",
    "storageZone": "xxxxxx",
    "adapter": "bunny"
  }
}

I get the Bad Gateway 502 on the front end
The following in the ghost error log, it doesnt really tell me whre the error is

“code”:“ERR_INVALID_ARG_TYPE”,“message”:“The "string" argument must be of type string or an instance of Buffer or ArrayBuffer. Received undefined”,“context”:“"Checking for updates failed, your site will continue to function."”,“help”:“"If you get this error repeatedly, please seek help from https://ghost.org/docs/\”",“stack”:“TypeError [ERR_INVALID_ARG_TYPE]: The "string" argument must be of type string or an instance of Buffer or ArrayBuffer. Received undefined\n at new NodeError (node:internal/errors:387:5)\n at Function.byteLength (node:buffer:740:11)\n at UpdateCheckService.updateCheckRequest (/var/www/ghost/versions/5.36.0/node_modules/@tryghost/update-check-service/lib/update-check-service.js:159:55)\n at processTicksAndRejections (node:internal/process/task_queues:96:5)\n at async UpdateCheckService.check (/var/www/ghost/versions/5.36.0/node_modules/@tryghost/update-check-service/lib/update-check-service.js:362:30)\n at async module.exports (/var/www/ghost/versions/5.36.0/core/server/update-check.js:60:5)”},“msg”:"The "string" argument must be of type string or an instance of Buffer or ArrayBuffer.

@vikaspotluri123 Thanks for the code edit. I implemented it but the same issue occurs

I didn’t make any code changes, just wrapped it into a code block to make reading it easier :slightly_smiling_face:

1 Like

Ooo :sweat_smile:
I thought some quotes were removed, the ones outlined in red so I removed those. This should be something simple to do…:sob:

It looks like you’re missing a comma after the closing bracket for paths and before storage.

Made the change but am still having issues. Am I on the right track? Seems like such a small piece of code to get wrong

Are you getting the same error? That error references an issue in your configuration. Are you editing the config in a code editor or checking that it’s properly formatted? You could also try adding back the default config, restarting Ghost, and seeing if your error goes away. Then, you’d know that the config file is your problem.

I’m getting the same error. If i remove the story entry from the config file it goes away

So you know, at least, that there’s an issue with your config. Did you try wrapping your storage config like this?

Yes, here it is
“storage”: {
“active”: “bunny”,
“bunny”: {
“cdnUrl”: “web.b-cdn.net”,
“storageUrl”: “storage.bunnycdn.com”,
“accessKey”: “xxxxxxx”,
“storageZone”: “xxxxxx”,
“adapter”: “bunny”
}

In this docs, they have it like this:

"adapters": {
  "storage": {
    "active": "storage-module-name",
    "storage-module-name": {
      "key": "value"
    }
  }
}

Have you wrapped the storage object with adapters?

Thanks, I tried that but it still gives the same issue. I have no syntax errors in the code so I’m not sure why it keeps giving the same error.

SOLVED - Hired a real Ghost dev rather than hacking my way through. Thanks all for the assistance

1 Like