What is the issue with my NodeJS Workflow action code for creating Zoho Leads in Slack?

This topic was automatically generated from Slack. You can find the original thread here.

Hi… I’ve been struggling to figure out what the issue is with the following code. I’m trying to debug an action by putting into a NodeJS Workflow step.

Nodejs workflow action

import pkg from '@slack/bolt';

// To use previous step data, pass the `steps` object to the run() function
export default {
    'name': 'Test Zoho Create Lead Slack Bolt Form Action',
    'description': 'Pipedream action for generating a Slack form for creation Zoho Leads',
    'type': 'action',
    'key': 'uniquesequence001',
    'version': '0.0.1',
    async run({ steps, $ }) {

        const leadMessageCallback = async ({ message, say }) => {
            try {

                // say() sends a message to the channel where the event was triggered
                console.log("processing message");
                await say(`Hey there <@${message.user}>!`);

            } catch (error) {
                console.error(error);
            }
        };

        const register = (app) => {
            app.message('hello', leadMessageCallback);
        };

        // Return data to use it in future steps
        const { App, ExpressReceiver } = pkg;

        // Format for generating a receiver event
        function generateReceiverEvent(payload) {
            return {
                body: payload,
                ack: async (response) => {
                    return {
                        statusCode: 200,
                        body: response ?? ""
                    };
                }
            };
        }


        var app;

        var appConfig = {
            token: process.env.TEST_SLACK_BOT_TOKEN,
            clientId: process.env.TEST_SLACK_CLIENT_ID,
            signingSecret: process.env.TEST_SLACK_SIGNING_SECRET,
            appToken: process.env.TEST_SLACK_APP_TOKEN
        };

        if (process.env['USE_SERVER'] == 'true') {
            // Web socket mode
            // add socketMode true and appToken for websockets
            appConfig = {
                ...appConfig, socketMode: true,
                appToken: process.env.TEST_SLACK_APP_TOKEN
            };

            app = new App(appConfig);
        } else {
            // Slack Event URL mode
            // add expressReceiver

            // Use Express Receiver
            const expressReceiver = new ExpressReceiver({
                signingSecret: process.env.TEST_SLACK_SIGNING_SECRET,
                processBeforeResponse: true
            });
            appConfig = { ...appConfig, receiver: expressReceiver };
            app = new App(appConfig);
        }


        // Register listener
        register(app);

        // Build payload from Event that triggered invocation
        const payload = steps.trigger.event.body;

        // Respond if Slack needs to verify the URL
        // Comment out once URL is verified to not require import util.
        /** if (util.isUrlVerificationRequest(payload)) {
           return {
             statusCode: 200,
             body: payload?.challenge
           };
         }**/
        // Detect if this is running as a Pipedream process, or as a local desktop process/using sockets
        if (process.env['USE_SERVER'] == 'true') {
            (async () => {
                // Run as a listner
                await app.start(process.env.PORT || 3000)
                console.log('App is running; listening for events from Slack / the web')
            })()
        } else {
            // Run as a single FaaS execution
            const slackEvent = generateReceiverEvent(payload);
            await app.processEvent(slackEvent);
            console.log("completed processing event..\n");
            return {
                statusCode: 200,
                body: ""
            }
        }
    }

}

The error is

Error
Apps used in a single workspace can be initialized with a token. Apps used in many workspaces should be initialized with oauth installer options or authorize. Since you have not provided a token or authorize, you might be missing one or more required oauth installer options. See https://slack.dev/bolt-js/concepts#authenticating-oauth for these required fields.  

at App.initAuthorizeIfNoTokenIsGiven (/tmp/__pdg__/dist/code/aa3a4149a3add1f4e5903633616a8768c9233a4576e59a1fa84108c556066102/node_modules/.pnpm/@slack+bolt@3.13.0/node_modules/@slack/bolt/dist/App.js:682:19)
    at App.initAuthorizeInConstructor (/tmp/__pdg__/dist/code/aa3a4149a3add1f4e5903633616a8768c9233a4576e59a1fa84108c556066102/node_modules/.pnpm/@slack+bolt@3.13.0/node_modules/@slack/bolt/dist/App.js:697:43)
    at [App.App](http://App.App) (/tmp/__pdg__/dist/code/aa3a4149a3add1f4e5903633616a8768c9233a4576e59a1fa84108c556066102/node_modules/.pnpm/@slack+bolt@3.13.0/node_modules/@slack/bolt/dist/App.js:159:35)
    at Object.run (file:///tmp/__pdg__/dist/code/aa3a4149a3add1f4e5903633616a8768c9233a4576e59a1fa84108c556066102/component.mjs:73:19)
    at global.executeComponent (/var/task/launch_worker.js:139:53)
    at MessagePort.messageHandler (/var/task/launch_worker.js:598:28)

But when I modify the code and remove the ‘key’ in the props, it works without error.

I also tried to publish this from pd publish, which is does so without error, but when I insert from myactions, I get the oAuth error when running.

Is there something unique to a key props that is conflicting?

    'name': 'Test Zoho Create Lead Slack Bolt Form Action',
    'description': 'Pipedream action for generating a Slack form for creation Zoho Leads',
    'type': 'action',
    'version': '0.0.1',

Thanks for your help

Hello , I think the error pointing you to this part:

        var appConfig = {
            token: process.env.TEST_SLACK_BOT_TOKEN,
            clientId: process.env.TEST_SLACK_CLIENT_ID,
            signingSecret: process.env.TEST_SLACK_SIGNING_SECRET,
            appToken: process.env.TEST_SLACK_APP_TOKEN
        };

May I ask if you have followed the tutorial here to add your environment variables?

Also, I see that you’re using @slack/bolt framework. I suspect this framework needed a long-running application running it. This code will basically starts a server listening for new events.

if (process.env['USE_SERVER'] == 'true') {
            (async () => {
                // Run as a listner
                await app.start(process.env.PORT || 3000)
                console.log('App is running; listening for events from Slack / the web')
            })()
        } else {

But it is not compatible with Pipedream, as Pipedream will run your whole workflow in a AWS Lambda function which have 15 minutes execution time limit. So at most your server will only run for 15 minutes.

For you usecase, I would recommend you to consider creating a new Workflow, add a Pipedream Slack’s trigger, and add action following your logic to call to some service or response a message using Pipedream Slack action

Hey thanks for taking a peek at this.

Re: Env variables:
In looking over the env variables documentation, I believe
process.env[‘USE_SERVER’] should be equivalent to process.env.USE_SERVER, or at least that’s what I see in my node environment. Do you see something different?

Re: the Bolt Listener:
Yes 100% this statement will not work correctly in Pipedream since it’s a listener, and hangs for too long.

await app.start(process.env.PORT || 3000)

The code is designed to look for an env variable USE_SERVER and if it exists (only set in a local environment), it uses the above listener for web sockets.

Otherwise it uses this set of statements which only processes a single event then ends. The is more of a FaaS environment that can’t run for a long period of time.

const slackEvent = generateReceiverEvent(payload);
await app.processEvent(slackEvent);

I’m still perplexed how removing the ‘key’ in the props
‘key’: ‘uniquesequence001’

in the code here, allows everything to work correctly and provide the right output.

, may I ask if you want to have a reusable action, or do you want just a one action in your workflow?

If you’d like to have a reusable action, you can refer to this doc here to have a clear guidance on it.

If you’d like to have a single action, you don’t need a key prop

Great question.
I put this in the nodeJS action so I can better debug. This is a small excerpt for the full action mjs.

I believe the only way to use the full action in Pipedream is to publish via pd publish - since it contains multiple nested mjs imports. Unless I’m mistaken, when publishing an action via PD, the key is needed, or is there another way?

I believe the only way to use the full action in Pipedream is to publish via pd publish - since it contains multiple nested mjs imports
Yes, to leverage all reusable action features you’ll need to use Pipedream CLI.

Unless I’m mistaken, when publishing an action via PD, the key is needed, or is there another way?
When you publish a reusable action, you’ll always need a key.

If your need is reusable action, I would strongly recommend you to read through this doc to have all context needed for your journey

Another option as I stated in the beginning, is develop a workflow and use Pipedream built-in triggers/actions instead of code. So that you don’t need to manage the code yourself

I’m not as tied to it being a re-usable action as needing to publish via PD (cli). I would like to stay with the bolt framework, given it’s flexibility, especially in building complex slack forms.

I’ll look at the documentation to see if there’s an alternate way to publish w/o requiring the key. Thanks!

Hey I did some other digging and found the issue. I was misunderstanding how actions get information from workflow triggers. This was a super valuable thread that was a huge unlock in understanding actions and how to get event data passed from previous steps