Access response Object in typescript class member function in Node.js - node.js

I want to use NextFunction(next() for accessing next middleware) in the member functions of the class for redirecting to next middleware after sending mail.
File : Errors.ts
import { NextFunction, Request, Response } from 'express';
export class SettlementErrors extends Error {
/**
* Constructs the SettlementErrors class
* #param {String} message an error message
* #param {Error} errorStack Error Stack
* #constructor
*/
private errorstack;
constructor(message:string,errorStack:Error) {
super(message);
this.errorstack = errorStack;
this.sendEmail();//Call this function without sending req,res,next as params
}
//Send Error Mail Want to access **next** Here
async sendEmail(request: Request, response: Response, next:NextFunction) : void
{
/**
Code For Sending Email
*/
}
}
How can I access next for switching to next middleware in member functions(function sendEmail) of this class ??
Thanks in advance

Related

Class 'Error' defines instance member property 'cause', but extended class 'TwirpError' defines it as instance member function

I am importing our gRPC service into my package and when I run yarn to install everything I get the following error message
node_modules/twirp-ts/build/twirp/errors.d.ts:28:5 - error TS2425: Class 'Error' defines instance member property 'cause', but extended class 'TwirpError' defines it as instance member function.
28 cause(): Error | undefined;
~~~~~
I installed twirp-ts in my companies gRPC go project using the following package.json and it got installed into the node_modules folder
{
"name": "events",
"version": "0.1.0",
"description": "Typescript implementation of the Twirp protocol",
"main": "./rpc/ts/index.ts",
"dependencies": {
"#protobuf-ts/plugin": "^2.2.3-alpha.1",
"ts-proto": "^1.126.1",
"twirp-ts": "^2.5.0"
}
}
Don't know why my package is throwing that error. Is there a tsconfig.json option I can use in my package to skip errors like this?
this is the code from errors.d.ts
/**
* Represents a twirp error
*/
export declare class TwirpError extends Error {
readonly msg: string;
readonly code: TwirpErrorCode;
readonly meta: Record<string, string>;
private _originalCause?;
constructor(code: TwirpErrorCode, msg: string);
/**
* Adds a metadata kv to the error
* #param key
* #param value
*/
withMeta(key: string, value: string): this;
/**
* Returns a single metadata value
* return "" if not found
* #param key
*/
getMeta(key: string): string;
/**
* Add the original error cause
* #param err
* #param addMeta
*/
withCause(err: Error, addMeta?: boolean): this;
cause(): Error | undefined;
/**
* Returns the error representation to JSON
*/
toJSON(): string;
/**
* Create a twirp error from an object
* #param obj
*/
static fromObject(obj: Record<string, any>): TwirpError;
}
/**
* NotFoundError constructor for the common NotFound error.
*/
export declare class NotFoundError extends TwirpError {
constructor(msg: string);
}
/**
* InvalidArgumentError constructor for the common InvalidArgument error. Can be
* used when an argument has invalid format, is a number out of range, is a bad
* option, etc).
*/
export declare class InvalidArgumentError extends TwirpError {
constructor(argument: string, validationMsg: string);
}
/**
* RequiredArgumentError is a more specific constructor for InvalidArgument
* error. Should be used when the argument is required (expected to have a
* non-zero value).
*/
export declare class RequiredArgumentError extends InvalidArgumentError {
constructor(argument: string);
}
/**
* InternalError constructor for the common Internal error. Should be used to
* specify that something bad or unexpected happened.
*/
export declare class InternalServerError extends TwirpError {
constructor(msg: string);
}
/**
* InternalErrorWith makes an internal error, wrapping the original error and using it
* for the error message, and with metadata "cause" with the original error type.
* This function is used by Twirp services to wrap non-Twirp errors as internal errors.
* The wrapped error can be extracted later with err.cause()
*/
export declare class InternalServerErrorWith extends InternalServerError {
constructor(err: Error);
}
/**
* A standard BadRoute Error
*/
export declare class BadRouteError extends TwirpError {
constructor(msg: string, method: string, url: string);
}
export declare enum TwirpErrorCode {
Canceled = "canceled",
Unknown = "unknown",
InvalidArgument = "invalid_argument",
Malformed = "malformed",
DeadlineExceeded = "deadline_exceeded",
NotFound = "not_found",
BadRoute = "bad_route",
AlreadyExists = "already_exists",
PermissionDenied = "permission_denied",
Unauthenticated = "unauthenticated",
ResourceExhausted = "resource_exhausted",
FailedPrecondition = "failed_precondition",
Aborted = "aborted",
OutOfRange = "out_of_range",
Unimplemented = "unimplemented",
Internal = "internal",
Unavailable = "unavailable",
DataLoss = "data_loss"
}
export declare function httpStatusFromErrorCode(code: TwirpErrorCode): number;
export declare function isValidErrorCode(code: TwirpErrorCode): boolean;

Chainlink any api - JSON to list of struct

I have an API that returns a JSON object as such:
[
{
"id": 2435,
"name": "First Last",
"email": "xxx#gmail.com",
"gender": "male",
"status": "inactive"
},
...
And I'm attempting to populate the response into a struct list variable (users) using Chainlink any API.
Please find below the contract code :
pragma solidity ^0.8.7;
import '#chainlink/contracts/src/v0.8/ChainlinkClient.sol';
import '#chainlink/contracts/src/v0.8/ConfirmedOwner.sol';
contract FetchFromArray is ChainlinkClient, ConfirmedOwner {
using Chainlink for Chainlink.Request;
string public jsonData;
bytes32 private jobId;
uint256 private fee;
User[] public users;
struct User{
uint256 id;
uint256 name;
uint256 email;
uint256 gender;
uint256 status;
}
event GetUsersData(bytes32 indexed requestId, string jsonData);
/**
* #notice Initialize the link token and target oracle
*
*
*/
constructor() ConfirmedOwner(msg.sender) {
setChainlinkToken(0x326C977E6efc84E512bB9C30f76E30c160eD06FB);
setChainlinkOracle(0xCC79157eb46F5624204f47AB42b3906cAA40eaB7);
jobId = '7d80a6386ef543a3abb52817f6707e3b';
fee = (1 * LINK_DIVISIBILITY) / 10; // 0,1 * 10**18 (Varies by network and job)
}
/**
* Create a Chainlink request to retrieve API response
*/
function getUser() public returns (bytes32 requestId){
Chainlink.Request memory req = buildChainlinkRequest(jobId, address(this), this.fulfill.selector);
// Set the URL to perform the GET request on
req.add('get', 'https://gorest.co.in/public/v2/users');
req.add('path', '$');
// Sends the request
return sendChainlinkRequest(req, fee);
}
/**
* Receive the response in the form of string
*/
function fulfill(bytes32 _requestId, string memory _jsonData) public recordChainlinkFulfillment(_requestId) {
emit GetUsersData(_requestId,_jsonData);
jsonData = _jsonData;
// users = TO DO popoluate users list
}
/**
* Allow withdraw of Link tokens from the contract
*/
function withdrawLink() public onlyOwner {
LinkTokenInterface link = LinkTokenInterface(chainlinkTokenAddress());
require(link.transfer(msg.sender, link.balanceOf(address(this))), 'Unable to transfer');
}
}
How do I add my json object to a struct?
Questions :
1 - Which jsonpath expression to use to retrieve the full json response of the api ? I tried req.add('path', '$') and req.add('path', '*'), but both didn't return the json.
2 - Once the full json is retrieved and stored in jsonData variable, how to parse it and insert the result in "User[] public users" variable ?

Application crash when calling container.get() in abstract class's constructor

I'm currently trying to implement a base class which has multiple properties. All but one property are being injected via the constructor using InversifyJS's #Inject tag. I'm also getting an instance via the container.Get() function in the constructor. When I run my application everything is fine, but when the application recieves a request, the app crashes without an error.
Base class
/**
* Base class for all intent logic
*/
#injectable()
export default abstract class IntentBase implements IIntent {
protected logger: ILogger;
protected responseService: IResponseService;
protected contextService: IContextService;
protected fallbackIntent: IIntent;
protected responseBuilder: IResponseBuilder;
/**
* Constructor
* #param logger logger
* #param responseService response service
* #param contextService context service
*/
constructor(
#inject(TYPES.WinstonLogger) logger: ILogger,
#inject(TYPES.ResponseService) responseService: IResponseService,
#inject(TYPES.ContextService) contextService: IContextService,
#inject(TYPES.ResponseBuilder) responseBuilder: IResponseBuilder,
) {
this.logger = logger;
this.responseService = responseService;
this.contextService = contextService;
this.responseBuilder = responseBuilder;
this.fallbackIntent = container.get(TYPES.DefaultFallbackIntent); // <-- container.Get() line
}
/**
* Override the standard fallback logic for an intent.
* #param fallback fallback to set
*/
setFallback(fallback: IIntent): void {
this.fallbackIntent = fallback;
}
When I uncomment the container.get(TYPES.DefaultFallbackIntent) line, my application can recieve requests like normally and it doesn't crash. The reason why I am trying this injection setup is because I'd like to set a default behavior for each child class in the constructor.
Does anyone have an explaination to why I cannot seem to inject this class?
Thanks in advance
Update
inversify.config.ts
import DefaultFallbackIntent from "./src/bot/intents/fallbacks/defaultFallbackIntent";
import TextResponseRepository from "./src/repositories/textResponseRepository";
import SsmlResponseRepsitory from "./src/repositories/ssmlResponseRepository";
import ContextService from "./src/services/contextService";
import GoogleResponseBuilder from "./src/builders/googleResponseBuilder";
const container = new Container();
container.bind<IGoogleAssistantController>(TYPES.GoogleController).to(GoogleAssistantController);
container.bind<IResponseService>(TYPES.ResponseService).to(ResponseSerivce);
container.bind<IContextService>(TYPES.ContextService).to(ContextService);
container.bind<IResponseRepository>(TYPES.TextResponseRepository).to(TextResponseRepository);
container.bind<IResponseRepository>(TYPES.SsmlResponseRepository).to(SsmlResponseRepsitory);
container.bind<ILogger>(TYPES.WinstonLogger).to(WinstonLogger);
container.bind<IIntent>(TYPES.WelcomeIntent).to(WelcomeIntent);
container.bind<IIntent>(TYPES.DefaultFallbackIntent).to(DefaultFallbackIntent);
container.bind<IResponseBuilder>(TYPES.ResponseBuilder).to(GoogleResponseBuilder);
export { container };
Default fallback intent
/**
* Default fallback intent class
*/
#injectable()
export default class DefaultFallbackIntent extends IntentBase {
invoke(conv: DialogflowConversation): DialogflowConversation {
const response = this.responseService.getResponse("defaultFallback");
return conv.ask(response);
}
}
In order for container.get(<Type>) to work, <Type> must be bound to the container at some point. In your composition root (where you set up your container) you can create this binding:
const container = new Container();
container.bind<IIntent>(TYPES.DefaultFallbackIntent)).to(<TheDefaultFallbackIntentClass>);
EDIT:
From the discussion in the comments it seems that DefaultFallbackIntent inherting from IntentBase is the problem, because at the time DefaultFallbackIntent gets instantiated (through binding it), there doesn't exist such an instance in the container when the base constructor is executed.
A workaround would be to not inherit from IntentBase and just implement the interface and set the required fields in this class as well:
/**
* Default fallback intent class
*/
#injectable()
export default class DefaultFallbackIntent implements IIntent {
protected logger: ILogger;
private responseService: IResponseService;
private contextService: IContextService;
private fallbackIntent: IIntent;
private responseBuilder: IResponseBuilder;
invoke(conv: DialogflowConversation): DialogflowConversation {
const response = this.responseService.getResponse("defaultFallback");
return conv.ask(response);
}
}
However, a better solution would be two create another super class which contains all the required fields both the default fallback intent and others have in order to reduce duplicated code.

How do I JSDoc custom EventEmitter on events in Visual Studio Code?

I've been working on a Node.js project and only just noticed that Visual Studio Code provides information about base EventEmitter objects. So I imagine it should be possible to provide JSDoc for custom ones too.
I've already attempted following the JSDoc http://usejsdoc.org/tags-event.html documentation but doesn't seem to pick up.
I don't know if this is effecting it but I'm using the ES6 class where the events get processed in a function outside it but it's inside the same script.
This is the test code.
// voice
if (voice) {
try {
/**
* Voice event.
*
* #event TelegramBot#voice
* #type {object}
* #property {object} chat - [object Chat]
* #property {number} date - Date when content was sent.
* #property {object} from - [object User]
* #property {number} message_id - Message id.
* #property {string} caption - Caption added to message. Value is undefined if none is added.
* #property {object} voice - [object Voice]
*/
context.emit('voice', chat, date, from, message_id, caption, voice)
} catch (error) {
context.emit('error', error)
}
}
I found this question while attempting to do the same, so I kept searching and I found a possible solution, by overriding the addListener methods, and documenting them.
I successfully made it work for both NodeJS and browser JS.
Result in VSCode
Typedef
First, create the typedef with your events names :
/**
* #typedef {["someEvent" | "someOtherEvent", ...any[]]} eventsDef
*/
I am using the spread syntax since I don't know how many arguments the user will pass to the method.
Implementation
For NodeJS:
The class needs to override the on and addListener methods, document the arguments, and simply call the parent's own method :
class Test extends EventEmitter {
/**
* #param {eventsDef} args
*/
addListener(...args) {
super.addListener(...args);
}
/**
* #param {eventsDef} args
*/
on(...args) {
super.on(...args);
}
fireEvent() {
this.emit("someEvent", "someValue");
}
}
Then you can use this class like so :
const t = new Test();
t.on("someEvent", (val) => console.log(val));
t.fireEvent(); // Outputs "someValue"
For the browser:
The class needs to extends EventTarget and override the addEventListener method.
Here is the snippet :
class Test extends EventTarget {
/**
* #param {["someEvent" | "someOtherEvent", ...any[]]} args
*/
addEventListener(...args) {
super.addEventListener(...args);
}
fireEvent() {
this.dispatchEvent(new CustomEvent("someEvent", {detail: "someValue"}))
}
}
const t = new Test();
t.addEventListener("someEvent", val => console.log(val.detail));
document.querySelector("button").addEventListener("click", () => {
t.fireEvent();
})
<button>Fire event</button>

Adding a new global variable in twig

I'm trying to get data for a new field added in login page. What I've done:
Modify AccountController.php login function adding new parameter: $this->_app->login($user, $client, !empty($data['rememberme']))
In Userfrosting.php login function i've set it in application: $this->client = $client;
In setupTwigUserVariables funtion added twig global: $twig->addGlobal("client", $this->client);
The problem is that in a template, {{client.id}} returns nothing. Any help will be appreciated.
In UserFrosting 4, you should create a Twig extension in your Sprinkle's src/Twig/ directory, and add the variable to the return value for getGlobals.
Your situation is a little tricky, since I'm not sure how client can be a global variable but at the same time depend on $data['client_id'] - which appears to be a request parameter. For now, I'll assume that you're submitting this parameter with any requests that require the client variable.
<?php
/**
* Stack Overflow
*
* #link https://stackoverflow.com
*/
namespace UserFrosting\Sprinkle\Site\Twig;
use Interop\Container\ContainerInterface;
use UserFrosting\Sprinkle\Site\Database\Models\Client;
/**
* Extends Twig functionality for the Site sprinkle.
*
* #author Jose Luis
*/
class Extension extends \Twig_Extension
{
protected $services;
protected $config;
public function __construct(ContainerInterface $services)
{
$this->services = $services;
$this->config = $services->config;
}
public function getName()
{
return 'myproject';
}
public function getGlobals()
{
try {
$currentUser = $this->services->currentUser;
// Assumes the client_id is being submitted as a query string (url) parameter
$clientId = $this->services->request->getQueryParam('client_id');
$client = Client::where('client_id', clientId)->where('userid', $currentUser->id)->first();
} catch (\Exception $e) {
$client = null;
}
return [
'client' => $client
];
}
}
You will then need to register this extension in your Sprinkle's service provider class:
<?php
/**
* Stack Overflow
*
* #link https://stackoverflow.com
*/
namespace UserFrosting\Sprinkle\Site\ServicesProvider;
use UserFrosting\Sprinkle\Site\Twig\Extension as JoseExtension;
/**
* Services provider for the Site sprinkle.
*
* #author Jose Luis
*/
class ServicesProvider
{
/**
* Register extended user fields services.
*
* #param Container $container A DI container implementing ArrayAccess and container-interop.
*/
public function register($container)
{
/**
* Extends the 'view' service with Jose's Twig Extension.
*/
$container->extend('view', function ($view, $c) {
$twig = $view->getEnvironment();
$extension = new JoseExtension($c);
$twig->addExtension($extension);
return $view;
});
}
}
Yes, I know that there is a lot of boilerplate here. However once you set these up the first time, it is easy to add new variables/functions/filters to the Twig environment and new services to your Sprinkle in the future.

Resources