Hi, I have a question about streams

I also have it, :S .env STREAMS_WEBHOOK_URL = '/streams-webhook'
init route local and stream url:

app.use(
   streamsSync(parseServer, {
     apiKey: config.MORALIS_API_KEY,
     webhookUrl: config.STREAMS_WEBHOOK_URL
}),

app for create stream:

app.post("/AuctionCreated", async (req: any, res: any) => {

   try {
     console.log("STREAMS_WEBHOOK_URL", `${url}${config.STREAMS_WEBHOOK_URL}`);
     const webHookUrl = `${url}${config.STREAMS_WEBHOOK_URL}`;
     const chaindIdFinal = chainID.testNet;

     const stream = await Moralis.Streams.add({
       chains: [EvmChain.MUMBAI],
       description: 'AuctionsCreated721',
       tag: 'AuctionsCreated',
       abi: marketAbi,
       includeContractLogs: true,
       topic0: [
         'AuctionCreated(address,uint256,uint8,uint256,uint256,uint256,address)'
       ],
       webhookUrl: webHookUrl,
       });

     const { id } = stream.toJSON();

     await Moralis.Streams.addAddress({
       address,
       id
     });

   } catch(e) {
     console.log("Not Moralis", e);
   }
   return res. send('ok');

})

initserver:

const httpServer = http.createServer(app);
httpServer.listen(config.PORT, async() => {
   if (config.USE_STREAMS) {
      url = await ngrok.connect(config.PORT);
     // eslint-disable-next-line no-console
     console.log(
       `Moralis Server is running on port ${config.PORT} and stream webhook url ${url}${config.STREAMS_WEBHOOK_URL}`,
     );
   } else {
     // eslint-disable-next-line no-console
     console.log(`Moralis Server is running on port ${config.PORT}.`);
   }
});

everything is fine, I don’t understand why it doesn’t work, I had ruled out ngrok because of the answers they gave me, that the error is my code, but the stream does not connect in any way, before changing the api, if I created the streams in the normal way , no longer, checking I realized that ngrok was not being created for me either, I went to the node_modules folder, look for ngrok/bin and configure the api there, with the command ngrok config add-authtoken xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx and if the ngrok url worked again, it returned the moralis server, that is, the ngrok error no longer gives me, but now I have one more question, a second question, the route to create the stream ( /streams-webhook ) does not work for me, and to configure the ngrok api How would it be done on a deployed server?

note: I think that between tests and local tests, I exhausted the number of ngrok, which I had by default.

I don’t think that you have to do this in code, just start ngrok in console

you can also separately ngrok with a simple local server to see if the requests make it to the server

1 Like

What you told me was key, thanks for the guide, that was the path, now I can identify on the route that I am not authorized on the route. when i stream and try to connect ngrok i get the following message in the log of ngrok:

401 Unauthorized

and when I hit prod in the moralis user interface I get the following message:

when i create the moralis event it responds fine but when i try to put in prod i get the error from the image above

but if I access for example the url http://localhost:1337/dashboard which would be with ngrok https://xxx-xxx-xxx-xx-xxx.ngrok-free.app/streams-webhook I have access normally, it is say ngrok works fine. Or do I have to configure something else? or because it tells me I am not authorized?

app.post("/streams-webhook", async (req: any, res: any) => {

  try {

    const { headers, body, tag  }: any = req;

    console.log('body', body);

    console.log('aqui2');

    const webhook: Types.IWebhook = req.body;

    console.log('aqui3');

      Moralis.Streams.verifySignature({

        body,

        signature: headers["x-signature"],

      });

    console.log('aqui4');

    return res.status(200).json();

  }catch(e){

    console.log("Not Moralis", e);

    return res.status(400).json();

  }

})

It looks like it is an issue with the signature, you have to validate the signature with the api key. You have to set the api key in code. Or the secret in case that the secret is not the api key. You can use an endpoint in the streams api swagger to see the secret used for the signature validation.

1 Like

hello cryptokid I have tried several things and the first thing is that moralis changed the interface and the old api did not grab it or at least there is a new api that says default, and when I take this one, now if I get to the server the event but I have several questions, doubts arose, the first question is:

because when i try to put the api in prod
2023-05-17_19h13_14

it throws me the following error:
2023-05-17_19h13_09
What is the difference between production and demo? and it should take this url, right? I couldn’t swagger
and the second question would be:

How do I extract the data to mongo db with parse-server? Is there any updated or functional example that I can follow please.
with the address of ngron, this is my index.ts:

/* eslint-disable @typescript-eslint/no-empty-function */

/* eslint-disable no-undef */

/* eslint-disable no-unused-expressions */

/* eslint-disable @typescript-eslint/no-explicit-any */

/* eslint-disable @typescript-eslint/no-var-requires */

/* eslint-disable no-console */

/* eslint-disable prefer-const */

/* eslint-disable @typescript-eslint/no-unused-vars */

import Moralis from 'moralis';

import express from 'express';

import cors from 'cors';

import config from './config';

import { parseServer } from './parseServer';

// @ts-ignore

import ParseServer from 'parse-server';

import http from 'http';

import { streamsSync } from '@moralisweb3/parse-server';

// @ts-ignore

import { Types } from '@moralisweb3/streams';

import { parseDashboard } from "./parseDashboard";

// @ts-ignore

import { BigNumber } from '@moralisweb3/core';

// @ts-ignore

import { EvmChain } from "@moralisweb3/evm-utils";

import { marketAbi } from './abi';

// @ts-ignore

import { verifySignatures } from './utils/verifySignature'

// @ts-ignore

import { contracts, chainID } from './config/moralis-connect'

import { json } from 'envalid';

const Web3 = require('web3');

let Transfer = require("./utils/TransferSchema").Transfers;

const connectDB  = require("./utils/ConectToDB").ConectToDB;

interface URI{

  value: string;

  id: BigNumber;

}

export const app = express();

let url = '';

const address = contracts.auction;

const web3 =  new Web3()

const port = config.PORT

Moralis.start({

  apiKey: config.MORALIS_API_KEY,

});

const verifySignature = (req: any, secret: any) => {

  const providedSignature = req.headers["x-signature"]

  if(!providedSignature) {throw new Error("Signature not provided")}

  const generatedSignature= web3.utils.sha3(JSON.stringify(req.body)+secret)

  if(generatedSignature !== providedSignature) {throw new Error("Invalid Signature")}

}

app.use(express.urlencoded({ extended: true }));

app.use(express.json());

app.use(cors());

app.use(

  streamsSync(parseServer, {

    apiKey: config.MORALIS_API_KEY,

    webhookUrl: config.STREAMS_WEBHOOK_URL

    }

  ),

);

app.use(`/server`, parseServer.app);

app.use(`/dashboard`, parseDashboard);

app.get('/streams', async (req: any, res: any) => {

  try {

    const response = await Moralis.Streams.getAll({limit: 0});

    console.log(response.raw);

  } catch (e) {

    console.error(e);

  }

})

app.listen(port, () => {

  console.log('escuchando streams')

})

app.post("/AuctionCreated", async (req: any, res: any) => {

  try {

    console.log("STREAMS_WEBHOOK_URL", `${url}${config.STREAMS_WEBHOOK_URL}`);

    const webHookUrl = `${url}${config.STREAMS_WEBHOOK_URL}`;

    const chaindIdFinal = chainID.testNet;

    const stream = await Moralis.Streams.add({

      chains: [EvmChain.MUMBAI],

      description: 'AuctionsCreated721',

      tag: 'AuctionsCreated',

      abi: marketAbi,

      includeContractLogs: true,

      topic0: [

        'AuctionCreated(address,uint256,uint8,uint256,uint256,uint256,address)'

      ],

      webhookUrl: webHookUrl,

      });

    const { id } = stream.toJSON();

    await Moralis.Streams.addAddress({

      address,

      id

    });

  } catch (e) {

    console.log("Not Moralis", e);

  }

  return res.send('ok');

})

const httpServer = http.createServer(app);

httpServer.listen(port, async () => {

  if (config.USE_STREAMS) {

    // eslint-disable-next-line no-console

    console.log(

      `Moralis Server is running on port ${port} and stream webhook url ${config.STREAMS_WEBHOOK_URL}`,

    );

  } else {

    // eslint-disable-next-line no-console

    console.log(`Moralis Server is running on port ${port}.`);

  }

});

// This will enable the Live Query real-time server

ParseServer.createLiveQueryServer(httpServer);

I also get an error for the listen:
error: undefined {"address":"::","code":"EADDRINUSE","errno":-4091,"port":1337,"syscall":"listen"}

and I think this problem is what happens to me https://forum.moralis.io/t/parse-server-post-instead-of-get-and-no-public-access-migration-config/22843/3 that parse server does not allow post because when I create the message it tells me that it cannot find that path. and I don’t see an updated repo of this, how do I save stream events in the db using parse server.

demo means that no webhook url will be used and the stream events will show directly in the admin interface, an internal webhook url will be used for that

prod means that the webhook requests will be sent to the webhook url that you specify, but first it will send a demo/test webhook request to that webhook url to check if the webhook url work, if the webhook url doesn’t respond with status code 200 to that test webhook request then the stream will not be updated to prod or with the new webhook url, in this case it look like the webhook url returned status code 401 instead of status code 200 for the test webhook requests

perfect, I understand now, so how can you see if it does the event but I can’t send the request to the specific url it doesn’t let me, therefore the server doesn’t receive anything, so the question is: my error, the one I’m dealing with from the beginning is when i create a stream

app.post("/streams", async() => {
   const { body } = req
   console. log(body);
})

and I try to open the route, it doesn’t let me, it tells me:
2023-05-18_03h16_09
2023-05-18_03h15_52

If I put the route to get if it opens the route for me, but in the same way moralis does not start the stream in prod then the error is from the route, I do not get a complete example or in video as it should be since I do things that are in the forum and I can’t make the stream work, sorry for the lack of knowledge. but I can’t find examples of stream working in the parse-server docu. And what I get I apply and it still doesn’t let me start prod the url.

Also try this:

https://forum.moralis.io/t/solved-how-i-can-get-logs-from-stream-using-self-hosting-server/22790/18?u=davidzuccarini

and that:
https://forum.moralis.io/t/using-event-syncs-in-moralis-sdk-v2-parse-server/20202
and I can’t get moralis the server to accept prod the url. I don’t see what else to do. help please :sob:

try with webhook.site as a webhook url, you will see there the complete request that will be sent to the webhook url, then you can try the same request with postman to your webhook url to see what happens

this may be expected behaviour, that url is not meant to be opened directly in the browser, are there more details about that response? why it doesn’t work?

notice that when it is like this:

export const app = express();
let url = '';
const address = contracts.auction;
const port = config.PORT
Moralis.start({
   apiKey: config.MORALIS_API_KEY,
});


app.use(express.urlencoded({ extended: true }));
app.use(express.json());

app.use(cors());

app.use(
   streamsSync(parseServer, {
     apiKey: config.MORALIS_API_KEY,
     webhookUrl: config.STREAMS_WEBHOOK_URL
     }
   ),
);

app.use(`/server`, parseServer.app);
app.use(`/dashboard`, parseDashboard);


app.post('/streams', (req: any, res: any) => {

     console.log('reqBody', req.body )
     return res.status(200).json();
  

})

app.listen(port, () => {

   console.log('listening to streams')

})

const httpServer = http.createServer(app);
httpServer.listen(port, async() => {
   if (config.USE_STREAMS) {
     // eslint-disable-next-line no-console
     console.log(
       `Moralis Server is running on port ${port} and stream webhook url ${config.STREAMS_WEBHOOK_URL}`,
     );
   } else {
     // eslint-disable-next-line no-console
     console.log(`Moralis Server is running on port ${port}.`);
   }
});

// This will enable the Live Query real-time server
ParseServer.createLiveQueryServer(httpServer);

it gives me this error:

2023-05-18_04h07_16

and ngrok reflects the following in the cmd:

when I switch with the code that I left, and I pass in the moralis interface to prod: ngrok responds: Unauthorized

2023-05-18_04h20_05 2023-05-18_04h20_18 2023-05-18_04h20_25

ok, it is related to the signature validation, you have to get the secret key from


you can set that secret key to the api key in case that it doesn’t have that value

thanks i try, but i have this type error:

Property 'raw' does not exist on type 'Promise<ResponseAdapter<{ region?: "us-east-1" | "us-west-2" | "eu-central-1" | "ap-southeast-1" | undefined; }, { region?: "us-east-1" | "us-west-2" | "eu-central-1" | "ap-southeast-1" | undefined; }>>'

app.post(`/streams`,  (req: any, res: any) => {

  const response = Moralis.Streams.readSettings({});

  console.log(response.raw);

    console.log('reqBody', req.body )

    return res.status(200).json();

 

})

Yes, at the beginning I pass the apikey in

Moralis.start({
   apiKey: config.MORALIS_API_KEY,
});

if i put it this way, and try again in the moralis interface do the same put it in prod the same error:

app.post(`/streams`, async (req: any, res: any) => {

   const response = await Moralis.Streams.readSettings();

   console.log(response.raw);
  
   console.log('reqBody', req.body )
   return res.status(200).json();


})

image

I don’t know what you mean, try to click on that url, you don’t have to change the code

https://docs.moralis.io/streams-api/evm/reference/get-settings

use directly the docs interface to read the secret and to update it if needed, you don’t have to change anything in code, you will need to use your api key in docs interface

I’m sorry if I didn’t ask the question correctly, English is not my native language, and I’m still learning, but, if I already made the request through the url you gave me, I already have the

{
   "region": "us-west-2",
   "secretKey": "xxxxxxx"
}

Now, what should I do, sorry too, I’m still learning from backend, I’m frontend.

try it this way:

app.post(`/streams`, async (req: any, res: any) => {

   verifySignature(req, secretKey)
  
   console.log('reqBody', req.body )
   return res.status(200).json();


})

and I try again to put it into production and without unauthorized success

:partying_face: :partying_face: :partying_face: :partying_face:
2023-05-18_05h36_26
Thank you very much for the guide and the help, it has already been put into production, it was the apikey and it is not the same from web3 to the one from streams, suggestion: they should unify the apikey, really thanks for the time, help and patience, now well , do i apply this? Using event-syncs in Moralis SDK v2 & Parse Server? I don’t understand this part how to do it,
const { filter, update, eventName } = realtimeUpsertParams(abi, log, req.body.confirmed, req.body.block);

Would this realtimeUpsertParams part be done as it says there?

What part of that code should I update to date? taking into account that there are approximately 8 events to be synchronized?