Troubleshooting TS2345 Error when building Loopback 4 application with JWT Authentication - loopbackjs

I'm try to integrate JWT authentication into my loopback 4 application. Right now I've been following the documentation here and the shopping tutorial, but I'm getting a strange build error when I'm registering my authentication strategy.
Here's my application.ts:
export class Application extends BootMixin(
ServiceMixin(RepositoryMixin(RestApplication)),
) {
constructor(options?: ApplicationConfig) {
super(options);
this.setUpBindings();
this.component(AuthenticationComponent);
registerAuthenticationStrategy(this, JWTAuthenticationStrategy);
this.sequence(MySequence);
// Set up default home page
this.static('/', path.join(__dirname, '../public'));
this.component(RestExplorerComponent);
this.projectRoot = __dirname;
// Customize #loopback/boot Booter Conventions here
this.bootOptions = {
controllers: {
// Customize ControllerBooter Conventions here
dirs: ['controllers'],
extensions: ['.controller.js'],
nested: true,
},
};
}
setUpBindings(): void {
// my bindings
}
}
The build script in my package.json (using #loopback/build)
"build": "lb-tsc -p tsconfig.build.json --target es2017 --outDir dist"
Here's the error I'm getting:
npm run build =>
src/application.ts:71:33 - error TS2345: Argument of type 'this' is not assignable to parameter of type 'Context'.
Type 'Application' is not assignable to type 'Context'.
Property 'registry' is protected but type 'Context' is not a class derived from 'Context'.
registerAuthenticationStrategy(this, JWTAuthenticationStrategy);
I am on Windows 10 using powershell.

I also had this same problem.
I was able to resolve by updating the # loopback / context dependency to the latest version through the command:
npm install --save #loopback/context
With the updated dependency the error disappears.

I found an answer here where you change registerAuthenticationStrategy(this, JWTAuthenticationStrategy); to registerAuthenticationStrategy(this as any, JWTAuthenticationStrategy);
export class Application extends BootMixin(
ServiceMixin(RepositoryMixin(RestApplication)),
) {
constructor(options?: ApplicationConfig) {
super(options);
this.setUpBindings();
this.component(AuthenticationComponent);
registerAuthenticationStrategy(this as any, JWTAuthenticationStrategy);
this.sequence(MySequence);
// Set up default home page
this.static('/', path.join(__dirname, '../public'));
this.component(RestExplorerComponent);
this.projectRoot = __dirname;
// Customize #loopback/boot Booter Conventions here
this.bootOptions = {
controllers: {
// Customize ControllerBooter Conventions here
dirs: ['controllers'],
extensions: ['.controller.js'],
nested: true,
},
};
}
setUpBindings(): void {
// my bindings
}
}
This fix worked for me.

Related

Unable to instrument expo app with istanbul or cypress/instrument

I have been trying this for a while now, without success.
I have an expo app and I am using cypress to test some use cases using the web version of the app (generated by expo).
However, I would like to generate some code coverage as well. I have read the official documentation for it, that recommends to babel-plugin-istanbul do to so, but it does not seem to work with expo.
I am not sure why this would not work.
Edit
I removed the files previously pointed here as they were not important.
Thanks for a wonderful documentation provided by a hero without a cape, I figured that my settings were wrong.
All I needed to do was:
install babel-plugin-istanbul
Update babel.config.js
module.exports = {
presets: ['babel-preset-expo'],
plugins: [
'istanbul',
[
'module-resolver',
{
root: ['.'],
extensions: [
'.js',
],
alias: {
'#': './',
},
},
],
],
};
update cypress/support/index.js
import '#cypress/code-coverage/support';
update cypress/plugins/index.js
module.exports = (on, config) => {
require('#cypress/code-coverage/task')(on, config);
// add other tasks to be registered here
// IMPORTANT to return the config object
// with the any changed environment variables
return config;
};
and voilĂ !

Django with Angular - relative paths when font and back have different url

After two days I failed to setup (any form of) webpack working with django3 in the back and angular10 in the front, so I decided to just use gulp to start ng serve for frontend and python manage.py runserver for backend. I am new to this, so this is probably very stupid but really two days is a lot of time to give on setup and get nothing back ..
Currently I am trying to call an API on the django server that is on http://127.0.0.1:8000 while ng serve is running on http://127.0.0.0:4200
#Injectable()
export class EchoService {
constructor(private httpClient: HttpClient) {}
public makeCall(): Observable<any> {
return this.httpClient.get<any>(
'http://127.0.0.1:8000/my-api/'
);
}
}
'''
Is there a better way how to do this in Angular without using "http://127.0.0.1:8000" in every component call I do? How can I make it as close as possible to relative paths, that will be used in the prod version of this (for prod I will just put the bundles manually in the html, but I can not do that manually for dev)
Angular allows defining an environment. Here is what I did:
in your src folder, find the environments folder.
create the following files and adjust the content as needed (there should already be a file named environment.ts there, I'll get back to that later. For now:
environment.dev.ts
export const environment = {
production: true,
apiURL: "http://127.0.0.1:8000/my-api"
};
environment.prod.ts
export const environment = {
production: true,
apiURL: "https://api.yoururl.com/"
};
modify your angular.json:
...
"configurations": {
...
"production": {
"outputPath": "dist-prod/",
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
}
"dev": {
"outputPath": "dist-dev/",
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.dev.ts"
}
],
}
...
For ng serve, the standard environment.ts file is used, so the contents should probably match those of environment.dev.ts.
You can create builds with this setup by just calling:
ng build --configuration dev
ng build --configuration prod
Use in your service/component:
import { environment } from 'your/path/environments/environment';
#Injectable()
export class EchoService {
constructor(private httpClient: HttpClient) {}
public makeCall(): Observable<any> {
return this.httpClient.get<any>(
environment.apiURL + 'your/endpoint/
);
}
}
Now, depending on the configuration, environment.apiURL might be 127.0.0.1:8000 or https://.....
I have one for development, one for staging, and one for production.
In case I`ve missed something, you can read about it here.

Ionic 2: How to use custom build Cordova Plugin

I'm already created cordova plugin and already used in Ionic 1, its worked. Then I tried to use it in Ionic 2 but I don't really know how to call that plugin. I follow the step from here to create my own plugin. And this is what i did:
plugin.xml
<name>myPlugin</name>
<js-module src="www/myPlugin.js" name="myPlugin">
<clobbers target="myPlugin" />
</js-module>
myPlugin.js
module.exports = {
myFunction: function (success, failure) {
cordova.exec(success, failure, "myPlugin", "myFunction", []);
}
};
hello-ionic.ts
import { Component } from '#angular/core';
declare var cordova: any;
#Component({
selector: 'page-hello-ionic',
templateUrl: 'hello-ionic.html'
})
export class HelloIonicPage {
constructor() {
}
click() {
if (typeof cordova !== 'undefined') {
cordova.plugins.myPlugin.myFunction();
}
}
}
But unfortunately it return me an error "Undefined myFunction" in hello-ionic.ts.
Here is what I did.
hello-ionic.ts
import { Component } from '#angular/core';
declare var myPlugin: any;
#Component({
selector: 'page-hello-ionic',
templateUrl: 'hello-ionic.html'
})
export class HelloIonicPage {
constructor() {
}
click() {
myPlugin.myFuntion(
(data) => {
console.log(data);
},
(err) => {
console.log(err);
});
}
}
declare var myPlugin: any; , myPlugin name I get from <clobbers target="myPlugin" />.
Note: Need to run the project in device only.
Following tutorial is a good resource to learn how to create custom cordova plugin :
https://taco.visualstudio.com/en-us/docs/createplugintutorial/
I have followed this tutorial to create multiple custom plugins and those are working fine in Ionic2.
One more thing to point out that the tutorial has not mentioned that:
You have to add your custom plugin in your ionic 2 project using following command:
ionic plugin add "folder path of your custom plugin"
Updated:
In your plugin.xml file, you have set "myPlugin" as target in clobbers tag.
So you should call your function as followed
window.myPlugin.myFunction();
Tip: Whenever you use custom plugin created by you(or someone else), inspect the application using Chrome Developer tools. In console tab of developer tools, you can inspect the window and other available objects and can find out correct way to call plugin's methods.

Ionic 2, Date Picker (cordova plugin). Property 'ANDROID_THEMES' does not exist on type 'typeof DatePicker'

I have installed the plugin Date Picker in my project.
In a component wich has import { DataPicker } from 'ionic-native' on top, if I use it like that (with androidTheme parameter commented) it WORKS:
let options = {
date: new Date(),
mode: 'date',
// androidTheme: DatePicker.ANDROID_THEMES.THEME_HOLO_LIGHT
};
DatePicker.show(options).then(
(date) => {
console.log('date_value:' + date)
}).catch( (error) => { });
If I uncomment androidTheme:DatePicker.ANDROID_THEMES.THEME_HOLO_LIGHT, It will bug during the building process throwing:
Property 'ANDROID_THEMES' does not exist on type 'typeof DatePicker'
I did a npm install ionic-native in CLI in my project folder as advised here but it did not fix the problem. It gives me the following output (that seems ok to me):
`-- ionic-native#2.0.3
npm WARN optional Skipping failed optional dependency /chokidar/fsevents:
npm WARN notsup Not compatible with your operating system or architecture: fsevents#1.0.15
When I look under [my project]\plugins\cordova-plugin-datepicker\www, it contains 3 folders corresponding to the 3 platforms (ios, android, windows) with each a JS file named 'DatePicker.js' and in the one below the android folder it contains in the code:
/**
* Android themes
*/
DatePicker.prototype.ANDROID_THEMES = {
THEME_TRADITIONAL : 1, // default
THEME_HOLO_DARK : 2,
THEME_HOLO_LIGHT : 3,
THEME_DEVICE_DEFAULT_DARK : 4,
THEME_DEVICE_DEFAULT_LIGHT : 5
};
If I look in [my project]\nodes_modules\ionic-native\dist\plugins\ , the file datepicker.js exists (of course) but does not contain the particularities of each platform.
What's wrong? Why datepicker.js under [my project]\nodes_modules\ionic-native\dist\plugins\ does not contain the particularity of each platform despite the plugin was added to the project?
I've found a work around for it:
in [my project]\nodes_modules\ionic-native\dist\plugins[android|ios|windows]\datepicker.js
At the end of the code it is written:
var datePicker = new DatePicker();
module.exports = datePicker;
// Make plugin work under window.plugins
if (!window.plugins) {
window.plugins = {};
}
if (!window.plugins.datePicker) {
window.plugins.datePicker = datePicker;
}
Hence, it makes datePicker (starting with lower case) different from DatePicker (starting with upper case from ionic-native).
In the component where I required it, I've just declare before the component:
declare var datePicker: any;
Then inside that component I've changed my code with:
let options = {
date: new Date(),
mode: 'date',
androidTheme: datePicker.ANDROID_THEMES.THEME_HOLO_LIGHT
};
DatePicker.show(options).then(
(date) => {
console.log('date_value:' + date)
}).catch( (error) => { });
It works.

ng2-translate fails on iOS device when trying to set language with NetworkError (DOM Exception 19): A network error occurred

I have been trying to figure out why Globalization.getPreferredLanguage() would fail only when running on an iOS device (not when running on a simulator or Android device / emulator)
Globalization.getPreferredLanguage().then((property) => {
let lang = property.value;
if (lang) {
if (lang.startsWith('en')){
this.translate.use('en_GB');
}
else if (lang.startsWith('fr')) {
this.translate.use('fr_FR');
}
else {
this.translate.use('en_GB');
}
} else {
console.log("property.value is null");
}
}).catch((reason) => {
this.translate.use('en_GB');// <-- not only does this NOT WORK, but the reason given is NetworkError (DOM Exception 19): A network error occurred.
});
What I have tried:
Removing and adding the Globalization plugin with both ionic and cordova instructions:
ionic plugin rm cordova-plugin-globalization && ionic plugin add
cordova-plugin-globalization
sudo cordova plugin rm cordova-plugin-globalization && sudo cordova plugin add cordova-plugin-globalization
EDIT 1
So after more debugging I can see it is the angular ng2-translate 'use' function that is failing. In my app.module.ts:
import { TranslateLoader, TranslateModule, TranslateStaticLoader } from 'ng2-translate/ng2-translate';
...
export function createTranslateLoader(http: Http) {
return new TranslateStaticLoader(http, '/assets/i18n', '.json');
}
...
#NgModule({
declarations: [
...
],
imports: [
...
BrowserModule,
HttpModule,
TranslateModule.forRoot({
provide: TranslateLoader,
useFactory: (createTranslateLoader),
deps: [Http]
}),
...
]
...
})
export class AppModule { }
But in my app.component.ts when I call
this.translate.use('en_GB');
It throws some exception. I have checked and the files do exist in the folder:
/.../platforms/ios/www/assets/i18n
For me, Globalization.getPreferredLanguage() is never resolved. So I am currently using
this.deviceLang = navigator.language;
This returns the device language with its variant like (FR-FR / EN-US)