NestJs Using Environment Configuration on #Cron decorator - javascript

I am building a nestJs application, with scheduling and configuration. I want to be able to configure my Cron with my environment variable but it does not seems to work.
app.module.ts :
#Module({
imports: [
ConfigModule.forRoot(),
ScheduleModule.forRoot(),
SchedulingModule,
...
],
})
export class AppModule {}
scheduling.service.ts (from my SchedulingModule) :
#Cron(process.env.CRON_VALUE)
scheduledJob() {
this.logger.log('Scheduled : Job');
...
}
.env :
...
CRON_VALUE=0 4 * * *
...
Apparently at the moment the value is checked it's empty. I got the following error :
(node:55016) UnhandledPromiseRejectionWarning: TypeError: Cannot read property '_isAMomentObject' of undefined
at new CronTime (/Users/antoinegrenard/Documents/Projet/b4finance/service-scheduling/node_modules/cron/lib/cron.js:42:50)
at new CronJob (/Users/antoinegrenard/Documents/Projet/b4finance/service-scheduling/node_modules/cron/lib/cron.js:527:19)
at /Users/antoinegrenard/Documents/Projet/b4finance/service-scheduling/node_modules/#nestjs/schedule/dist/scheduler.orchestrator.js:56:29
...

Apparently it is not possible to get env values in decorators.
I had to do it this way :
constructor(private schedulerRegistry: SchedulerRegistry) {}
onModuleInit() {
const job = new CronJob(process.env. CRON_VALUE, () => {
// What you want to do here
});
this.schedulerRegistry.addCronJob(name, job);
job.start();
}

To fix this problem you should load the config on your service again:
require('dotenv').config();

Related

How to use injected providers in a controller with a packaged dynamic module in nestjs

I couldn't seem to find any related question to my problem on here, so i decided to ask my first question, please be gentle :>
I want to provide an endpoint for frontend logging in several of our backends that use nestjs.
To solve this, i want to use a dynamic module that exposes said endpoint and package it as an npm package to be used in other applications.
I inject a logger into the controller via an injection token and the logging service via nestjs standard dependency injection.
The problem now is, after publishing the module, installing it in another application, the service i injected via nestjs standard DI is undefined.
I tried to follow the nestjs documentation as closly as possible when it comes to dynamic modules.
I also tried to retrieve the service via ModuleRef, but still the same problem. In this case, moduleRef is undefined.
Here is basically all of the involved code:
frontend-log.module.ts:
import { DynamicModule, Module } from "#nestjs/common";
import { FrontendLogService } from "./frontend-log.service";
import { Logger } from "./interfaces/logger";
import { FrontendLogController } from "./frontend-log.controller";
#Module({})
export class FrontendLogModule {
static forRoot(logger: Logger): DynamicModule {
return {
module: FrontendLogModule,
controllers: [FrontendLogController],
providers: [FrontendLogService, { provide: "LOGGER", useValue: logger }],
};
}
}
frontend-log.controller.ts:
import { Body, Controller, Inject, Post, Req } from "#nestjs/common";
import { FrontendLogMessage } from "../model/frontend-log-message";
import { Request } from "express";
import { RequestWithToken } from "../model/request-with-token";
import { Logger } from "./interfaces/logger";
import { ArrayMaxSize, ArrayMinSize, ValidateNested } from "class-validator";
import { Type } from "class-transformer";
import { FrontendLogService } from "./frontend-log.service";
class FrontendLogData {
#Type(() => FrontendLogMessage)
#ArrayMinSize(1)
#ArrayMaxSize(20)
#ValidateNested({ each: true })
messages: FrontendLogMessage[];
}
#Controller()
export class FrontendLogController {
constructor(
#Inject("LOGGER") private logger: Logger,
private logService: FrontendLogService
) {}
#Post("log")
public log(#Req() req: Request, #Body() data: FrontendLogData) {
this.logService.logFrontendMessages( // logService is undefined here
this.logger,
data.messages,
(req as RequestWithToken).kauth.grant.access_token.content
);
}
}
frontend-log.service.ts:
import { Injectable } from "#nestjs/common";
import { FrontendLogMessage } from "../model/frontend-log-message";
import { AccessTokenContent } from "../model/request-with-token";
import { Logger } from "./interfaces/logger";
#Injectable()
export class FrontendLogService {
public logFrontendMessages(
logger: Logger,
data: FrontendLogMessage[],
accessToken?: AccessTokenContent
) {
const user = accessToken
? `${accessToken.name} (${accessToken.sub})`
: "anonymous";
data.forEach((logEntry) => {
logger.log(logEntry.level, `[FRONTEND] [${user}] ${logEntry.message}`);
});
}
}
I then build the package and publish it.
After installing it in the consuming project I import the frontend-log.module into the AppModule as follows:
#Module({
imports: [
// ...
FrontendLogModule.forRoot(getLogger('debug')),
],
controllers: [
// ...
],
providers: [
// ...
],
})
export class AppModule implements NestModule {
// ...
}
When i then try to post to the /log endpoint via Postman, the following error occurs:
[Nest] 15280 - 26.10.2022, 09:03:50 ERROR [ExceptionsHandler] Cannot read properties of undefined (reading 'logFrontendMessages')
TypeError: Cannot read properties of undefined (reading 'logFrontendMessages')
at FrontendLogController.log
This tells me, the frontend-log.controller works properly, since the log endpoint is exposed as expected.
So my question: What am I doing wrong here, is there something i am not considering, when it comes to publishing nestjs Modules over npm? Or am I doing some rookie mistake here?

Angularjs and Angular 8 hybrid and execute code micronization get Error: Can't resolve all parameters for xxx-service

I have a difficult case which was organized from an old angularjs and angular8, besides it's was also limited in the extensive refactoring to resolve in code of micronization.And the code of angularjs cannot be changed.
In the end I choose the library ngx-planet that is closest to my situation, but i got this error
Issue:
When I then local run it, I get this error message.
I have tested this way of writing under angularjs and angular8 code without planet library, it can work, but after using planet, the aforementioned error occurred.
After searching, it was found that the reasons for this error message are known as the following 6 types:
Barrel index
Circularity dependency
Forgot to enable polyfills import'core-js/es6/reflect'
Injectable decorator incorrect usage (EX: missing # or capital & lower case error etc...)
Tsconfig does not configure emitDecoratorMetadata
Decorate parameter type use any in your constructor
The first 5 have been excluded, I suspect it is the last, because of this Configuring Dependency Injection in Angular
But I am confused, whether a certain configuration of planet causes parameter type to fail?
Code Structure:
1. There is a common service exported from angularjs
(File name: angular1-root-module.js)
(function () {
angular.module('angular1', [
'angular1.export-service'
]);
angular.module('angular1.export-service', []);
angular.module('angular1.export-service').factory('Angular1ExportService', Angular1ExportService);
Angular1ExportService.$inject = [];
function Angular1ExportService() {
function outPutString() {
return 'I from Angular1 export service string';
}
return {
outPutAngular1String: outPutString,
};
}
})();
2. Inject into the class named Angular1InjectorService through the factory provider and depend on angularjs's $injector
export function Angular1InjectorServiceFactory(injector: any) {
return new Angular1InjectorService(injector);
}
export const Angular1InjectorServiceProvider = {
provide: Angular1InjectorService,
useFactory: Angular1InjectorServiceFactory,
deps: ['$injector']
};
#Injectable()
export class Angular1InjectorService {
// I think probably this injector of type is any cause
constructor(private angular1Injector: any) {
}
getService(serviceName: String) {
return this.angular1Injector.get(serviceName);
}
}
3. Then inject into the common AppBaseService
#Injectable()
export class AppBaseService {
readonly angular1InjectorService: Angular1InjectorService;
readonly testService: any;
constructor(readonly injector: Injector) {
this.angular1InjectorService = this.injector.get(Angular1InjectorService);
this.testService = this.angular1InjectorService.getService('Angular1ExportService');
}
testGetAngular1String() {
console.log('app base service is work!');
return this.testService.outPutAngular1String();
}
}
4. Then the service of the sub app inherits AppBaseService, and obtains the method that exists in angularjs
export class App1RootService extends AppBaseService {
constructor(readonly injector: Injector) {
super(injector);
}
GetLogAngular1String() {
console.log('app1 root service is work!');
return this.testGetAngular1String();
}
}
5. Portal root planet config
this.planet.registerApps([
{
name: 'app1',
hostParent: '#app-host-container',
routerPathPrefix: '/app1',
selector: 'app1-root-container',
resourcePathPrefix: '/static/app1',
preload: settings.app1.preload,
switchMode: settings.app1.switchMode,
loadSerial: true,
manifest: '/static/app1/manifest.json',
scripts: [
'main.js'
],
styles: [
],
}
]);
6. Sub app1 main config
defineApplication('app1', (portalApp: PlanetPortalApplication) => {
return platformBrowserDynamic([
{
provide: PlanetPortalApplication,
useValue: portalApp
},
{
provide: AppRootContext,
useValue: portalApp.data.appRootContext
}
])
.bootstrapModule(App1RootModule)
.then(appModule => {
return appModule;
})
.catch(error => {
console.error(error);
return null;
});
});
Issue related resources:
EXCEPTION: Can't resolve all parameters
Uncaught Error: Can't resolve all parameters for
After upgrade Angular to v8: Can't resolve all parameters for Component:
Intact issue code:
Stackblitz
Github
I have not found an answer, and already have the official github open issue, but hope to get more help
Thanks.

Sapper. How to globally use third-party libraries

I want to access a variable gun in server and client side.
This is my module:
import Gun from 'gun/gun'
import Sea from 'gun/sea' // eslint-disable-line no-unused-vars
export const gun = Gun({
localStorage: true,
radisk: true,
peers: ['http://localhost:8765/gun']
})
If it was a Nuxt, which I want to abandon in favor of a Sapper, I would have implemented it like this:
import Gun from 'gun/gun'
import 'gun/sea'
import 'gun/lib/open'
const gun = Gun({
localStorage: true,
radisk: true,
peers: ['http://localhost:8765/gun']
})
export default ({ app }, inject) => {
inject('gun', () => gun)
}
// nuxt.config.js
...
plugins: [{ src: '#/plugins/gun.js' }]
...
Thus, I would get access to the $gun everywhere:
On the server side:
export default {
asyncData(context){
context.app.$gun()
}
}
And on the client side:
methods: {
submit() {
const gun = this.$gun()
const user = this.$gun().user()
...
}
}
And also in the template:
<template>
<div>{{ $gun }}</div>
</tempalte>
This question does not concern the use of the specific library that is being discussed in the question (gun). It can be a Websocet connection (then we would pass the ws variable sun in the same way.), or an rpc (to connect with Bitcoin) - I can give many examples where this can be important.
Somewhere I read that you need to implement this through the rollbar, somewhere I read about a regular module (es6 or .svelte) - but then I encounter a number of other problems ...
I don't really see the direct question, but I'll just guess... you're trying to use a global variable in svelte (moving from nuxt)?
Svelte uses rollup, and you should have a .rollup.config.js file in your root.
export default {
...
plugins: [
svelte({
// magic happens here
})
]
}
More documentation on (what I think your issue is) including globals.
https://svelte.dev/docs#Compile_time
&
https://github.com/rollup/rollup-plugin-svelte

API client in Javascript

I need a little help to solve a problem in my project.
Scenario:
First: I have a SPA web site that is being developed in Vue.js.
Second: I also have a Web API spec in Swagger that I want to use to generate my client code in Javascript.
Lastly: I'm using swagger-codegen-cli.jar for that.
What I've done until now
1 - Download the last swagger-codegen-cli.jar stable version with javascript support:
curl http://central.maven.org/maven2/io/swagger/swagger-codegen-cli/2.4.7/swagger-codegen-cli-2.4.7.jar -o swagger-codegen-cli.jar
2 - Generate the client code using:
java -jar swagger-codegen-cli.jar generate -i http://192.168.0.85:32839/api/swagger/v1/swagger.json -l javascript -o ./web_api_client/
3 - Add the generated module to my project:
"dependencies": {
// ...
"vue": "^2.6.10",
"vue-router": "^3.0.3",
"web_api_client": "file:./web_api_client"
},
4 - Execute npm install. Apparently, it's working fine.
5 - At this moment I faced the problem. For some reason, the module generated isn't loaded completely.
export default {
name: 'home',
components: {
HelloWorld
},
mounted() {
var WebApiClient = require("web_api_client");
var defaultClient = WebApiClient.ApiClient.instance;
var oauth2 = defaultClient.authentications["oauth2"];
oauth2.accessToken = "YOUR ACCESS TOKEN";
var apiInstance = new WebApiClient.VersaoApi();
var callback = function(error, data, response) {
if (error) {
console.error(error);
} else {
console.log('API called successfully. Returned data: ' + data);
}
};
apiInstance.apiVersaoGet(callback);
}
}
6 - The line var WebApiClient = require("web_api_client"); is working without any error, however, not working 100%. The instance of the module has been created but empty. For instance, WebApiClient.ApiClient is always undefined.
7 - I took a look at the generated code and I think the problem is related with the way the module is being loaded.
(function(factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['ApiClient', 'api/VersaoApi'], factory);
} else if (typeof module === 'object' && module.exports) {
// CommonJS-like environments that support module.exports, like Node.
module.exports = factory(require('./ApiClient'), require('./api/VersaoApi'));
}
}(function(ApiClient, VersaoApi) {
'use strict';
// ...
In this code, neither of ifs blocks are executed.
Has someone faced a problem like that?
Some advice?
Many thanks, folks.
Solution
After a while trying to fix the problem with require("web_api_client"); I decided to use ES6 instead ES5.
I found an option in swagger-codegen-cli.jar to generate the client code using ES6 as shown below:
java -jar swagger-codegen-cli.jar generate -i http://192.168.0.85:32839/api/swagger/v1/swagger.json -l javascript --additional-properties useES6=true -o ./web_api_client/
Using ES6 I was able to import the javascript module direct from the generated source as shown in the code below.
import WebApiClient from "./web_api_client/src/index";
let defaultClient = WebApiClient.ApiClient.instance;
defaultClient.basePath = 'http://192.168.0.85:32839';
// Configure OAuth2 access token for authorization: oauth2
let oauth2 = defaultClient.authentications["oauth2"];
oauth2.accessToken = "YOUR ACCESS TOKEN";
let apiInstance = new WebApiClient.VersaoApi();
apiInstance.apiVersaoGet((error, data, response) => {
if (error) {
console.error(error);
} else {
console.log("API called successfully. Returned data: " + data + response);
}
});
When I first ran the code I got an error because the module WebApiClient generated didn't have the keyword default in the export block.
Original generated code
export {
/**
* The ApiClient constructor.
* #property {module:ApiClient}
*/
ApiClient,
// ...
Alter changed
export default {
/**
* The ApiClient constructor.
* #property {module:ApiClient}
*/
ApiClient,
// ...
Now everything is working fine.

How to correctly configure unit tests for Probot with Scheduler Extension?

I am using the following minimal probot app and try to write Mocha unit tests for it.
Unfortunately, it results in the error below, which indicates that some of my setup for the private key or security tokens is not picked up.
I assume that the configuration with my .env file is correct since I do not get the same error when I start the probot via probot-run.js.
Are there any extra steps needed to configure probot when used with Mocha?
Any suggestions on why the use of the scheduler extension may result in such issue would be great.
Code and error below:
app.ts
import createScheduler from "probot-scheduler";
import { Application } from "probot";
export = (app: Application) => {
createScheduler(app, {
delay: !!process.env.DISABLE_DELAY, // delay is enabled on first run
interval: 24 * 60 * 60 * 1000 // 1 day
});
app.on("schedule.repository", async function (context) {
app.log.info("schedule.repository");
const result = await context.github.pullRequests.list({owner: "owner", repo: "test"});
app.log.info(result);
});
};
test.ts
import createApp from "../src/app";
import nock from "nock";
import { Probot } from "probot";
nock.disableNetConnect();
describe("my scenario", function() {
let probot: Probot;
beforeEach(function() {
probot = new Probot({});
const app = probot.load(createApp);
});
it("basic feature", async function() {
await probot.receive({name: "schedule.repository", payload: {action: "foo"}});
});
});
This unfortunately results in the following error:
Error: secretOrPrivateKey must have a value
at Object.module.exports [as sign] (node_modules/jsonwebtoken/sign.js:101:20)
at Application.app (node_modules/probot/lib/github-app.js:15:39)
at Application.<anonymous> (node_modules/probot/lib/application.js:260:72)
at step (node_modules/probot/lib/application.js:40:23)
at Object.next (node_modules/probot/lib/application.js:21:53)
Turns out that new Probot({}); as suggested in the documentation initializes the Probot object without any parameters (the given options object {} is empty after all).
To avoid the error, one can provide the information manually:
new Probot({
cert: "...",
secret: "...",
id: 12345
});

Categories

Resources