Shopify / shopify-app-js

MIT License
280 stars 111 forks source link

TypeError: scopesArray.map is not a function #93

Closed dongido001 closed 1 year ago

dongido001 commented 1 year ago

Issue summary

In this shopify.js file of the CLI 3 template, I tried using the MongoDBSessionStorage session storage but I was getting an error:

/Users//projects/buyonecolective-main/node_modules/@shopify/shopify-api/lib/auth/scopes/index.js:18 2023-01-12 17:52:09 | backend | .map(function (scope) { return scope.trim(); }) 2023-01-12 17:52:09 | backend | ^ 2023-01-12 17:52:09 | backend | 2023-01-12 17:52:09 | backend | TypeError: scopesArray.map is not a function 2023-01-12 17:52:09 | backend | at new AuthScopes (/Users//projects/-main/node_modules/@shopify/shopify-api/lib/auth/scopes/index.js:18:14) 2023-01-12 17:52:09 | backend | at Session.isActive (/Users//projects/-main/node_modules/@shopify/shopify-api/lib/session/session.js:80:77) 2023-01-12 17:52:09 | backend | at /Users//projects/*-main/web/node_modules/@shopify/shopify-app-express/build/cjs/middlewares/validate-authenticated-session.js:57:79 2023-01-12 17:52:09 | backend | at process.processTicksAndRejections (node:internal/process/task_queues:95:5) 2023-01-12 17:52:09 | backend | 2023-01-12 17:52:09 | backend | Node.js v18.12.1 2023-01-12 17:52:09 | backend | [nodemon] app crashed - waiting for file changes before starting... 2023-01-12 17:52:09 | frontend | 18:52:09 [vite] http proxy error:

Expected behavior

shopify.validateAuthenticatedSession() should not break the app.

Actual behavior

App crashes when calling shopify.validateAuthenticatedSession()

Issue is most likely from the MongoDBSessionStorage class. I tweaked it a bit and it worked for me. The way it returns the Session in the loadSession method does not seem right.

cjpwrs commented 1 year ago

I was seeing the same error with the postgres adapter, upgrading @shopify/shopify-app-express to version 1.2.0 fixed it for me

xiguan00yu commented 1 year ago

same error. Cannot be fixed even after upgrading @shopify/shopify-app-express to 1.2.0. @cjpwrs Could you provide more information? I'm interested in the way you did the restoration. thanks you.

mkevinosullivan commented 1 year ago

Issue is most likely from the MongoDBSessionStorage class. I tweaked it a bit and it worked for me. The way it returns the Session in the loadSession method does not seem right.

@dongido001 Can you elaborate on this comment please? What tweak did you apply to get it working for you?

mkevinosullivan commented 1 year ago

@cjpwrs @xiguan00yu What version of the @shopify/shopify-app-session-storage-mongodb package are you using?

dongido001 commented 1 year ago

@mkevinosullivan

I copied out the code - 'mongodb.ts', then modified it a bit:

import * as mongodb from 'mongodb';
import { Session } from '@shopify/shopify-api';

const defaultMongoDBSessionStorageOptions = {
    sessionCollectionName: 'shopify_sessions'
};

export class MongoDBSessionStorage {
    constructor(dbUrl, opts = {}) {
        this.isConnected = false
        this.isConnecting = false
        this.dbUrl = dbUrl
        this.options = { ...defaultMongoDBSessionStorageOptions, ...opts };
        this.ready = this.init();
    }

    async storeSession(session) {
        await this.ready;

        await this.collection.findOneAndReplace(
            { id: session.id },
            session.toObject(),
            {
                upsert: true,
            },
        );
        return true;
    }

    async loadSession(id) {
        await this.ready;

        const result = await this.collection.findOne({ id });

        return result ? new Session.fromPropertyArray(Object.entries(result)) : undefined;
    }

    async deleteSession(id) {
        await this.ready;
        await this.collection.deleteOne({ id });
        return true;
    }

    async deleteSessions(ids) {
        await this.ready;
        await this.collection.deleteMany({ id: { $in: ids } });
        return true;
    }

    async findSessionsByShop(shop) {
        await this.ready;

        const rawResults = await this.collection.find({ shop }).toArray();
        if (!rawResults || rawResults?.length === 0) return [];

        return rawResults.map((rawResult) => new Session(rawResult));
    }

    async disconnect() {
        await this.client.close();
    }

    get collection() {
        return this.client
            .db(this.dbName)
            .collection(this.options.sessionCollectionName);
    }

    async init() {
        this.isConnecting = true
        try {
            this.client = new mongodb.MongoClient(this.dbUrl);
            await this.client.connect();
            await this.client.db().command({ ping: 1 });
            await this.createCollection();
            this.isConnected = true
            return this.client
        } catch (e) {
            throw new Error(e)
        } finally {
            this.isConnected = false
            this.isConnecting = false
        }
    }

    async tryToInit(count = 0) {
        if (this.isConnected) {
            return this.client
        }

        if (this.isConnecting && count < 4) {
            console.log("still trying to connect to mongo... ", count)
            setTimeout(() => {
                this.tryToInit(count + 1)
            }, 6000)
        }

        return await this.init()
    }

    async hasSessionCollection() {
        const collections = await this.client.db().collections();
        return collections
            .map((collection) => collection.collectionName)
            .includes(this.options.sessionCollectionName);
    }

    async createCollection() {
        const hasSessionCollection = await this.hasSessionCollection();
        if (!hasSessionCollection) {
            await this.client.db().collection(this.options.sessionCollectionName);
        }
    }
}

The most important thing here that I modified for the bug is the loadSession method

zaaack93 commented 1 year ago

I 'm facing the same issue , is there someone have a solution for this ?

CamilaAlvarez commented 1 year ago

I believe the issue is due to @shopify/shopify-app-express and @shopify/shopify-app-session-storage-mongodb using incompatible versions of @shopify/shopify-api. Try updating @shopify/shopify-app-express to 2.0.0

TomTweakCommerce commented 1 year ago

I believe the issue is due to @shopify/shopify-app-express and @shopify/shopify-app-session-storage-mongodb using incompatible versions of @shopify/shopify-api. Try updating @shopify/shopify-app-express to 2.0.0

This solved it for me, great job @CamilaAlvarez ! I'm using the shopify-app-session-storage-sqlite (not mongodb) and for me the solution was to change in web/package.json the dependencies to "@shopify/shopify-app-express": "^2.0.0", It was the issue right after creating a new app template using npm init @shopify/app@latest which shouldn't happen...

mkevinosullivan commented 1 year ago

Fixes merged in and released with @shopify/shopify-api@7.1.0 and @shopify/shopify-app-express@2.1.1