I'm implementing pusher in a web application using nextjs. It works as expected in my development environment. But it does not work correctly when I deploy it to vercel. I can only see the results when I refresh the page in the browser.
This is the implementation for the client:
useEffect(() => {
const pusher = new Pusher(`${process.env.PUSHER_KEY}`, {
cluster: `${process.env.PUSHER_CLUSTER}`,
useTLS: true
});
const channel = pusher.subscribe('franks-auto-spa');
channel.bind('cancel-wash', data => {
console.log(data.date);
removeWash(data.date);
});
}, []);
And this is the implementation for the API:
export default async (req, res) => {
const connection = await mysql.createConnection(process.env.DATABASE_URL);
console.log(req.body.date);
const result = await connection.query('DELETE FROM ongoing WHERE date = ?', [req.body.date]);
console.log(result);
const pusher = new Pusher({
appId: `${process.env.PUSHER_ID}`,
key: `${process.env.PUSHER_KEY}`,
secret: `${process.env.PUSHER_SECRET}`,
cluster: `${process.env.PUSHER_CLUSTER}`,
useTLS: true
});
pusher.trigger('franks-auto-spa', 'cancel-wash', req.body);
res.json({message: 'Wash deleted deleted...'});
}
Am I missing any configuration in Vercel?
I've had this problem too, once or twice; Vercel times out after a little bit. (10 seconds on Hobby) So using a database with Vercel probably isn't gonna fly. Have you tried switching to the Pro plan? Or you could switch to Heroku, which not only has a longer timeout (30 seconds), but also supports websockets.
Related
I've integrate BrainTree Drop-in UI for checkout payment in nodeJS. It's only a demonstration that I needed to create. I had no issues, it was easy enough. The only thing that I would like to do is to hide merchantId, publicKey and privateKey from the code. I would like to add them directly in Heroku Config Vars. I know how to do all this in Python, but I have no idea how to do it in JavaScript. I show you the code changing the keys:
const express = require('express');
const router = express.Router();
const braintree = require('braintree');
router.post('/', (req, res, next) => {
const gateway = new braintree.BraintreeGateway({
environment: braintree.Environment.Sandbox,
// Use your own credentials from the sandbox Control Panel here
merchantId: 'h43jgh5g3gl4543',
publicKey: 'hj45j4h5lh45hl4h5l',
privateKey: 'b5hbhbb45bhbh4kfndnfdkkfnd'
});
// Use the payment method nonce here
const nonceFromTheClient = req.body.paymentMethodNonce;
// Create a new transaction for $10
const newTransaction = gateway.transaction.sale({
amount: '10.00',
paymentMethodNonce: nonceFromTheClient,
options: {
// This option requests the funds from the transaction
// once it has been authorized successfully
submitForSettlement: true
}
}, (error, result) => {
if (result) {
res.send(result);
} else {
res.status(500).send(error);
}
});
});
module.exports = router;
How can I assign those values to Variables that I can then pass to Heroku Config Vars?
Thank you very much for your help!
EDITING THE INTIAL POST:
Sorry I need to add more info about this post. I followed what a user suggested by changing the code in Node.js in this way:
router.post('/', (req, res, next) => {
const gateway = new braintree.BraintreeGateway({
environment: braintree.Environment.Sandbox,
// Use your own credentials from the sandbox Control Panel here
merchantId: process.env.MERCHANT_ID,
publicKey: process.env.PUBLIC_KEY,
privateKey: process.env.PRIVATE_KEY
});
I added those value to Heroku, and it looked it was working, but I also changed the sandbox value in index.hbs:
<script>
var button = document.querySelector('#submit-button');
braintree.dropin.create({
authorization: process.env.SANDBOX_KEY,
container: '#dropin-container',
paypal: {
flow: 'checkout',
buttonStyle: {
color: 'blue',
shape: 'rect',
size: 'medium'
},
amount: '10.00',
currency: 'USD'
}
},
I replace the value 'sanbox_34920hfjh34i23h4oi3' with process.env.SANDBOX_KEY and added that value in Heroku.
But now the interface doesn't work anymore, why?
Thank you very much for your precious help!
You can add Config variables in Heroku dashboard or with the CLI more on that here Configuration and Config Vars. Now, when you done that you can access them in your Node app as process.env.NAME_OF_VARIABLE.
I am building a nodejs api that uses fastify, Prisma and Postgres. I have the API working with fastify-cookies and fastify-session and i can get cookies just fine but i need to be able to store the session cookies in the database. I saw a tutorial on doing this but it was without prisma, so im lost on how to connect fastify-session to the Prisma database pool.
I user the prisma client to connect to the database to do my normal calls in my routes, const data = await prisma.model.create({});
server.js
const fastify = require('fastify')({ logger: true });
const PORT = process.env.PORT || 3000;
// Session state
fastify.register(require('./sessions'));
// Register all our routes here.
...
// Startup code for the fastify server.
const start = async () => {
try {
await fastify.listen(PORT, '0.0.0.0');
} catch (error) {
fastify.log.error(error);
process.exit(1);
}
};
// Start the fastify server.
start();
sessions.js
const cookie = require('fastify-cookie');
const session = require('fastify-session');
const fp = require('fastify-plugin');
/**
* #param {import('fastify').FastifyInstance} fastify
*/
const plugin = async (fastify) => {
// All plugin data here is global to fastify.
fastify.register(cookie);
fastify.register(session, {
secret: process.env.SESSION_SECRET,
store: new SessionStore({
tableName: 'UserSession',
pool: ???, <--------------------------------- how to connect?
}),
saveUninitialized: false,
cookie: {
httpOnly: true,
secure: false,
},
});
fastify.addHook('preHandler', (req, reply, next) => {
req.session.user = {};
next();
});
};
module.exports = fp(plugin);
If you want to use the Prisma connection pool you would have to create a session storage library similar to connect-pg-simple or modify the codebase to accept a Prisma connection. This is definitely a non-trivial implementation and I don't think it would make a lot of sense without exceptional circumstances.
I would suggest creating a new pg.Pool or pgPromise instance and connecting with that like it was shown in the tutorial video you linked to. There's no reason you can't have two separate connection pools open to the same database (One with Prisma and one with pg.Pool)
So I'm following https://shopify.dev/tutorials/build-a-shopify-app-with-node-and-react but ever since I ngrok'd it's too slow.
Is there any way I can develop locally? I know Shopify is a hosted solution but ngrok makes it way too slow for me.
I'm from India & I think the servers are from US & it's so slow that it takes literally 5 mins & sometimes it doesn't even load properly at all.
Here's my current server.js:
require('isomorphic-fetch')
const dotenv = require('dotenv')
const Koa = require('koa')
const next = require('next')
const { default: createShopifyAuth } = require('#shopify/koa-shopify-auth')
const { verifyRequest } = require('#shopify/koa-shopify-auth')
const session = require('koa-session')
dotenv.config()
const { PORT, NODE_ENV, SHOPIFY_API_SECRET_KEY, SHOPIFY_API_KEY } = process.env
const port = parseInt(PORT, 10) || 3000
const dev = NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare().then(() => {
const server = new Koa()
server.use(session({ secure: true, sameSite: 'none' }, server))
server.keys = [SHOPIFY_API_SECRET_KEY]
server.use(
createShopifyAuth({
apiKey: SHOPIFY_API_KEY,
secret: SHOPIFY_API_SECRET_KEY,
scopes: ['read_products'],
afterAuth(ctx) {
const { shop, accessToken } = ctx.session
ctx.cookies.set('shopOrigin', shop, {
httpOnly: false,
secure: true,
sameSite: 'none',
})
ctx.redirect('/')
},
})
)
server.use(verifyRequest())
server.use(async (ctx) => {
await handle(ctx.req, ctx.res)
ctx.respond = false
ctx.res.statusCode = 200
return
})
server.listen(port, () => {
console.log(`> Ready on http://localhost:${port}`)
})
})
Can I set the dev variable somewhere & bypass Shopify auth (Idk much about koa) to code my app locally & then check the final result on Shopify app store?
I even tried serveo, lynk, sish & many other ngrok alternatives. None of them worked. serveo did until it didn't. So I gotta use 8 hours of ngrok but any other solutions are appreciated.
To determine if the website is online I plan on making a simple ping script and returning a boolean through a REST endpoint or having the phone check periodically for an updated value; but I feel like there has to be a better way. What's the best way to notify the device of a change? Is there a way to make the endpoint send a push notification to a react-native app if the boolean returns true; or a 200 status?
const express = require('express')
const domainPing = require('domain-ping')
const port = 4000
const app = express()
cron.schedule("* * * * *", function() {
domainPing("example.com")
.then(resp => resp)
/*
* resp: {domain: "example.com", ip: "93.184.216.34", online: true, ping: false, statusCode: 200, success: true}
* */
return [resp.online, resp.status] //How can I send a push notification here to react-native?
.catch(err => {
console.log(err)
});
});
app.listen(port, () => console.log(`http://localhost:${port}!`))
After following all the steps from start to finish provided by Microsoft (Tutorial here: https://learn.microsoft.com/en-us/azure/bot-service/javascript/bot-builder-javascript-quickstart?view=azure-bot-service-4.0 ) I've setup the continuous deployment via GIT which works fine.
I've been able to run the code on my localhost and Bot Framework Emulator without any issues. I've also been able to run the bot using the web chat channel iframe provided on the Azure platform.
( https:// webchat.botframework.com/embed/{your-bot}?s={secret})
Lastly I'm also able to run the bot using the "test in web chat" option via Azure.
However, when I try to use the URL provided by azure to test my bot I get the following:
https://{your-domain}.azurewebsites.net/api/messages
{"code":"MethodNotAllowed","message":"GET is not allowed"}
And from https://{your-domain}.azurewebsites.net
{"code":"ResourceNotFound","message":"/ does not exist"}
I've scoured the internet trying to find a solution, all the solutions that I found are using the old version of the framework and point towards a server.get method not being present in index.js.
If there's any more information that I can provide please let me know.
Here's the code from index.js
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
// index.js is used to setup and configure your bot
// Import required packages
const path = require('path');
const restify = require('restify');
// Import required bot services. See https://aka.ms/bot-services to learn more about the different parts of a bot.
const { BotFrameworkAdapter, ConversationState, InputHints, MemoryStorage, UserState } = require('botbuilder');
const { FlightBookingRecognizer } = require('./dialogs/flightBookingRecognizer');
// This bot's main dialog.
const { DialogAndWelcomeBot } = require('./bots/dialogAndWelcomeBot');
const { MainDialog } = require('./dialogs/mainDialog');
// the bot's booking dialog
const { BookingDialog } = require('./dialogs/bookingDialog');
const BOOKING_DIALOG = 'bookingDialog';
// Note: Ensure you have a .env file and include LuisAppId, LuisAPIKey and LuisAPIHostName.
const ENV_FILE = path.join(__dirname, '.env');
require('dotenv').config({ path: ENV_FILE });
// Create adapter.
// See https://aka.ms/about-bot-adapter to learn more about adapters.
const adapter = new BotFrameworkAdapter({
appId: process.env.MicrosoftAppId,
appPassword: process.env.MicrosoftAppPassword
});
// Catch-all for errors.
adapter.onTurnError = async (context, error) => {
// This check writes out errors to console log
// NOTE: In production environment, you should consider logging this to Azure
// application insights.
console.error(`\n [onTurnError]: ${ error }`);
// Send a message to the user
const onTurnErrorMessage = `Sorry, it looks like something went wrong!`;
await context.sendActivity(onTurnErrorMessage, onTurnErrorMessage, InputHints.ExpectingInput);
// Clear out state
await conversationState.delete(context);
};
// Define a state store for your bot. See https://aka.ms/about-bot-state to learn more about using MemoryStorage.
// A bot requires a state store to persist the dialog and user state between messages.
// For local development, in-memory storage is used.
// CAUTION: The Memory Storage used here is for local bot debugging only. When the bot
// is restarted, anything stored in memory will be gone.
const memoryStorage = new MemoryStorage();
const conversationState = new ConversationState(memoryStorage);
const userState = new UserState(memoryStorage);
// If configured, pass in the FlightBookingRecognizer. (Defining it externally allows it to be mocked for tests)
const { LuisAppId, LuisAPIKey, LuisAPIHostName } = process.env;
const luisConfig = { applicationId: LuisAppId, endpointKey: LuisAPIKey, endpoint: `https://${ LuisAPIHostName }` };
const luisRecognizer = new FlightBookingRecognizer(luisConfig);
// Create the main dialog.
const bookingDialog = new BookingDialog(BOOKING_DIALOG);
const dialog = new MainDialog(luisRecognizer, bookingDialog);
const bot = new DialogAndWelcomeBot(conversationState, userState, dialog);
// Create HTTP server
const server = restify.createServer();
server.listen(process.env.port || process.env.PORT || 3978, function() {
console.log(`\n${ server.name } listening to ${ server.url }`);
console.log(`\nGet Bot Framework Emulator: https://aka.ms/botframework-emulator`);
console.log(`\nTo test your bot, see: https://aka.ms/debug-with-emulator`);
});
// Listen for incoming activities and route them to your bot main dialog.
server.post('/api/messages', (req, res) => {
// Route received a request to adapter for processing
adapter.processActivity(req, res, async (turnContext) => {
// route to bot activity handler.
await bot.run(turnContext);
});
});
The Bot Framework /api/messages endpoint is configured to accept POST requests. Navigating to https://{your-domain}.azurewebsites.net/api/messages is a GET request, which is why are getting the "Resource not found" response. The "Resource not found" response actually tells you that your bot is running. If the web app wasn't running or the initial deployment failed, you would see a "The resource you are looking for has been removed, had its name changed, or is temporarily unavailable" message. As long as Test in Web Chat works, you are good to go!
If you want to add a static HTML page to your server, there are a few changes I would recommend adding to your bot.
Direct Line Token Endpoint
First, you should add another endpoint to your bot to generate a Direct Line Token. Here is a basic implementation. For more details I recommend you take a look at the Direct Line Authentication documentation.
// DirectLine Token
server.post('/directline/token', async (req, res) => {
const id = (req.body && req.body.id)? `dl_${req.body.id}`: `dl_default_user`
const options = {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.directLineSecret}`,
'Content-Type': 'application/json',
},
url: 'https://directline.botframework.com/v3/directline/tokens/generate',
data: {
user: { id }
}
};
try {
const { data } = await axios(options);
res.send(data);
} catch ({ message }) {
res.status(403);
res.send({ message });
}
});
Serve Static Files
Next, create a public file in your root directory and add a new endpoint to your bot with the Restify serveStatic plugin. Take a look at the Restify Plugin documentation for more details.
server.get('/*', restify.plugins.serveStatic({
directory: path.join(__dirname, 'public'),
default: 'index.html'
}));
index.html
Finally, in your public directory, create an index.html and add the following code. It is configured to request a token from your /directline/token endpoint and render an instance of Web Chat.
<!DOCTYPE html>
<html lang="en-US">
<head>
<title>Web Chat: Full-featured bundle</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.botframework.com/botframework-webchat/latest/webchat.js"></script>
<style>
html, body { height: 100% }
body { margin: 0 }
#webchat {
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<div id="webchat" role="main"></div>
<script>
(async function () {
const res = await fetch('/directline/token', { method: 'POST' });
const { token } = await res.json();
window.WebChat.renderWebChat({
directLine: window.WebChat.createDirectLine({ token })
}, document.getElementById('webchat'));
document.querySelector('#webchat > *').focus();
})().catch(err => console.error(err));
</script>
</body>
</html>
Hope this helps!