Developing Upload Provider with Typescript

System Information
  • Strapi Version: 4.25.4
  • Operating System: Mac/Unix
  • Database: Postgres
  • Node Version: 18.19.1
  • NPM Version: 10.2.4
  • Yarn Version: -

I’m starting work on a custom Strapi upload provider for box.com, whose SDK is in TypeScript. When I run my server I get the following error:

TypeError: provider.init is not a function                                                                                                              │
│       at createProvider (/Users/erikmadsen/Documents/Projects/SBM/sbm-strapi/node_modules/@strapi/plugin-upload/server/register.js:60:37)                 │
│       at module.exports [as register] (/Users/erikmadsen/Documents/Projects/SBM/sbm-strapi/node_modules/@strapi/plugin-upload/server/register.js:16:38)   │
│       at Object.register (/Users/erikmadsen/Documents/Projects/SBM/sbm-strapi/node_modules/@strapi/strapi/dist/core/domain/module/index.js:46:46)         │
│       at Object.register (/Users/erikmadsen/Documents/Projects/SBM/sbm-strapi/node_modules/@strapi/strapi/dist/core/registries/modules.js:28:19)          │
│       at async Strapi.runLifecyclesFunctions (/Users/erikmadsen/Documents/Projects/SBM/sbm-strapi/node_modules/@strapi/strapi/dist/Strapi.js:440:5)       │
│       at async Strapi.register (/Users/erikmadsen/Documents/Projects/SBM/sbm-strapi/node_modules/@strapi/strapi/dist/Strapi.js:361:5)                     │
│       at async Strapi.load (/Users/erikmadsen/Documents/Projects/SBM/sbm-strapi/node_modules/@strapi/strapi/dist/Strapi.js:425:5)                         │
│       at async Object.develop (/Users/erikmadsen/Documents/Projects/SBM/sbm-strapi/node_modules/@strapi/admin/dist/_chunks/index-sNH2VWbC.js:837:28)      │
│       at async develop (/Users/erikmadsen/Documents/Projects/SBM/sbm-strapi/node_modules/@strapi/admin/dist/_chunks/develop-YNTGWKMC.js:61:5)             │
│       at async Command.parseAsync (/Users/erikmadsen/Documents/Projects/SBM/sbm-strapi/node_modules/commander/lib/command.js:923:5)

Steps to reproduce the behavior

Provider is at providers/strapi-provider-upload-box/index.ts

Builds to dist/providers/strapi-provider-upload-box/index.js

package.json

"devDependencies": {
    "ajv": "^8.17.1",
    "strapi-provider-upload-box": "file:./dist/providers/strapi-provider-upload-box"
  },

plugins.js

module.exports = ({env}) => ({
    upload: {
        config: {
            provider: 'strapi-provider-upload-box',
            providerOptions: {
                clientId: env('BOX_CLIENT_ID'),
                clientSecret: env('BOX_CLIENT_SECRET'),
                enterpriseId: env('BOX_ENTERPRISE_ID'),
                publicKeyId: env('BOX_PUBLIC_KEY_ID'),
                privateKey: env('BOX_PRIVATE_KEY'),
                privateKeyPassphrase: env('BOX_PRIVATE_KEY_PASSPHRASE'),
                jwtAlgorithm: 'RS256',
                boxUserId: env('BOX_USER_ID')
            }
        }
    }
});

dist/providers/strapi-provider-upload-box/index.js

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
// providers/upload-provider-box/index.ts
const { BoxJwtAuth, JwtConfig, BoxClient } = require('box-typescript-sdk-gen');
exports.default = {
    init(providerConfig) {
        const jwtConfig = new JwtConfig({
            clientId: providerConfig.clientId,
            clientSecret: providerConfig.clientSecret,
            enterpriseId: providerConfig.enterpriseId,
            publicKeyId: providerConfig.publicKeyId,
            privateKey: providerConfig.privateKey,
            privateKeyPassphrase: providerConfig.privateKeyPassphrase,
            jwtAlgorithm: 'RS256',
        });
        const jwtAuth = new BoxJwtAuth({ config: jwtConfig });
        const userAuth = jwtAuth.withUserSubject(providerConfig.boxUserId);
        const client = new BoxClient({ auth: userAuth });
        return {
            upload(file) {
                return new Promise((resolve, reject) => {
                    /* My implementation */
                });
            },
            delete(file) {
                return new Promise((resolve, reject) => {
                    /* My implementation */
                });
            },
        };
    },
};