n8n node development: "No testing function found for this credential." - n8n

I'm busy building my own node that connects to Oracle, and stumbled upon this problem...
I have a credentials file that does not contain any authentication or testing methods, as I am declaring a separate testing function in the node.ts file. When testing my node, it keeps saying that my credentials don't have a corresponding test function.
In my node.ts file I am stating that my credentials be tested by a function called testConnection:
credentials: [
{
name: 'myConnection',
required: true,
testedBy: 'testConnection'
}
],
which is declared in my node's methods object like so:
methods = {
listSearch: {
searchTables
},
//the credential test function is declared here:
credentialTest: {
testConnection /** this function is imported from another file */
}
};
My test function follows the ICredentialsTestFunction interface signature that looks like this:
export declare type ICredentialTestFunction = (this: ICredentialTestFunctions, credential: ICredentialsDecrypted) => Promise<INodeCredentialTestResult>;
I've checked how MySQL and other similar nodes are doing it and I expected my code to work correctly as theirs do, yet it does not recognize the test function.
What am I doing wrong?

Related

Why does Uniswap interface use multiple Web3Provider?

I was learning how to develop a front end for dApps by going through the code for Uniswap interface.
Then I found that there are two Web3Providers used in the app like below.
<Web3ReactProvider getLibrary={getLibrary}> // 1st
<Web3ProviderNetwork getLibrary={getLibrary}> // 2nd
<Blocklist>
// some other child nodes
</Blocklist>
<Web3ProviderNetwork>
</Web3ReactProvider>
As for Web3ReactProvider, it uses the component provided by the web3-react package, while Web3ProviderNetwork is created with a key "NETWORK" on the same file those providers are written.
Uniswap has a method useActiveWeb3React which returns web3context values depending on its active variable value.
In other words, default web3Context is returned if active variable is true, otherwise Web3Context with Network is returned. (code below)
export default function useActiveWeb3React() {
const interfaceContext = useWeb3React<Web3Provider>()
const interfaceNetworkContext = useWeb3React<Web3Provider>(
process.env.REACT_APP_IS_WIDGET ? undefined : NetworkContextName
)
if (interfaceContext.active) {
return interfaceContext
}
return interfaceNetworkContext
}
Does anyone know why they switch providers depending on the active variable?
Does it make any difference?

I passed a class to my front-end project through electron's preload, but I couldn't create an instance?

the error displayed:
Can't the class constructor ABC be called without "new"
frontend:
"vite": "^2.1.2",
"vite-plugin-html": "^2.1.0",
"vite-plugin-vue2": "^1.4.2"
vue2
electron 14
I create a class and use preload like this:
const { contextBridge } = require('electron')
class ABC {
constructor() {
this.item = {}
}
update() {
console.log(`<<<<2021年09月16日 13:56:33>>>>`, this)
}
}
contextBridge.exposeInMainWorld('$electron', {
ABC
})
and I get ABC in my frontend:
const {ABC } = window.$electron
const abc = new ABC()
But console throw an error that Class constructor ABC cannot be invoked without 'new'
You cannot expose complex types like Object via the contextBridge.
Only object properties that are considered 'simple' or a function are made available. The documentation states:
The api provided to exposeInMainWorld must be a Function, string, number, Array, boolean, or an object whose keys are strings and values are a Function, string, number, Array, boolean.
The contextBridge will gut your class of methods and only retain properties. The documentation also states:
Function values are proxied to the other context and all other values are copied and frozen. Any data / primitives sent in the API become immutable and updates on either side of the bridge do not result in an update on the other side.
This is another reason why classes will not work, they're typically passed by reference.
See the table of supported parameters, errors and return types.

NestJS - question regarding service-mocking

I'm currently rewriting our plain node API-server in NestJS and I've encountered the following issue: I have a CacheService which acts as a wrapper around redis and which is injected in various other services.
Now, if the client-request contains a custom-header (key: x-mock-redis, value: someRedisMockKey) and if the server runs in debug mode, instead of calling redis, a mocked json-value should be returned (the value is read from a file with the name someRedisMockKey).
I could set the scope of my CacheService to "Request" and inject the client-request, allowing me to check if the mocking-header exists and return the mocked value there if running in debug-mode.
But I find this counterintuitive as I'd have logic violating the single responsibility principle and which should not run in production-mode. Also I'd prefer my CacheService to have default scope instead of "Request".
Any recommendations how to do this more elegantly?
In advance, sorry if I misunderstood the question or constraints, will try to paraphrase them and point out how it should look like, I suppose.
production always uses Redis
you can set up the app instance on different port so that it is fully separated from 'staging' (or other) app instance
If you can fulfill the second condition, you can make use of custom modules and apply different client-wrapper (strategy) for your service:
Custom provider for Cache module
import * as redis from 'redis'
import { INTERNAL_CACHE_CLIENT, INTERNAL_CACHE_MODULE } from './cache.constants'
import { CacheModuleAsyncOptions, InternalCacheOptions } from './cache.module'
import CacheClientRedis from './client/cache-client-redis'
// ...
export const createAsyncClientOptions = (options: CacheModuleAsyncOptions) => ({
provide: INTERNAL_CACHE_MODULE,
useFactory: options.useFactory,
inject: options.inject,
})
export const createClient = () => ({
provide: INTERNAL_CACHE_CLIENT,
useFactory: (options: InternalCacheOptions) => {
const { production, debug, noCache, ...redisConfig } = options
// pardon for the ifs ; )
if (noCache) {
return new CacheClientInMemory()
}
if (production) {
return new CacheClientRedis(redis.createClient(redisConfig))
}
if (debug) {
return new MockedCache()
}
return new CacheClientMemory()
},
inject: [INTERNAL_CACHE_MODULE],
})
as noticed, you can have any wrapper around CacheClient, which, in your case, would serve data from file. For simplicity, the example of interface being implemented by any cache client could be:
export interface CacheClient {
set: (key: string, payload: string) => Promise<boolean>
get: (key: string) => Promise<string | null>
del: (key: string) => Promise<boolean>
}
Now on, as we have let the module decide which strategy should be used, service just needs:
constructor(
#Inject(INTERNAL_CACHE_CLIENT) private readonly cacheClient: CacheClient) {
}
Feel free to point out if it still breaks principles or you really need to decide it during runtime.
Cheers!

Chrome 71 AudioContext resuming with Twilio Client

With the Chrome 71 changes that start audiocontext's in a suspended state, we need to resume the audio context after a user interaction. We are handling this by displaying a red banner at the top of our website saying we need you to grant us permission to enable calling with a button. The button meets the user engagement so we can resume the audio context.
The issue I am having is that the device which I have already called device.setup() on does not have the audioContext available when the user clicks the button.
I should be able to access the audioContext through device.audio.audioContext and call the resume() method on it, but what I get instead is undefined.
Currently as a workaround I am calling device.audio._audioContext.resume() and this is never undefined and works. But it seems to me like there is some bug where the public accessor for audioContext is not being defined in the twilio-client library. Or am I doing something wrong here?
In the es5 compiled code I see the following in the device.js file I see
Object.defineProperty(Device, "audioContext", {
/**
* The AudioContext to be used by {#link Device} instances.
*/
get: function () {
return Device._audioContext;
},
enumerable: true,
configurable: true
});
I get undefined when calling this. However, the device.audio property is set in this bit of code, where it passes Device.audioContext as an option:
this.audio = new (this.options.AudioHelper || AudioHelper)
(this._updateSinkIds, this._updateInputStream, getUserMedia, {
audioContext: Device.audioContext,
enabledSounds: this._enabledSounds,
logEnabled: !!this.options.debug,
logWarnings: !!this.options.warnings,
});
And then in the audiohelper.js file the constructor calls:
Object.defineProperties(this, {
_audioContext: {
value: audioContext
},
// more stuff
},
so it seems like when the device is initially created the Device.audioContext is in existence and is passed through to audio._audioContext, but later Device.audioContext loses its reference to the audio context.
Twilio developer evangelist here.
This may be a failure of documentation or communication, but I think I know what is going on now.
Device.audioContext is a public method on the Device class. As you discovered in the code it is defined here:
Object.defineProperty(Device, "audioContext", {
/**
* The AudioContext to be used by {#link Device} instances.
*/
get: function () {
return Device._audioContext;
},
enumerable: true,
configurable: true
});
Note that this defines the audioContext property on the Device object itself.
But there is no definition for audioContext on instances of Device. This is why your code in the gist you posted fails when you try to call state.device.audioContext.
As you point out, the audio object on the device object is created using Device.audioContext. So, you can actually drop using the pseudo-private device.audio._audioContext and just use the public Device.audioContext when you want to resume().
I would rewrite to:
resumeTwilioDevice = async () => {
Twilio.Device.audioContext.resume();
};

Angular library - Type 'Subject<any[]>' is not assignable to type 'Subject<any[]>'

I've been following this guide to create a custom angular library but I've hit a wall with an issue rather odd.
The idea behind exercise is simple, create a skeleton for a particular piece of functionality (in this case a staff directory) where a developer can npm install it and provide a custom data source that implements our interface.
This interface is as follows
export interface ISDDataService {
refiners: Subject<Refiner[]>;
search(queryTxt: string): Observable<Staff[]>;
refine(refiner: Refiner): Observable<Staff[]>;
}
In the library project, this skeleton is a module referenced by the root module which is set up to provide the data source which inherits the ISDDataService
#Injectable()
export class AppService implements ISDDataService {
refiners: Subject<Refiner[]>;
staff: Staff[] = [];
constructor() {
this.staff.push(<Staff>{name: 'John Doe', role: 'xyz', group: 'A Team', image: ''});
this.staff.push(<Staff>{name: 'Jane Doe', role: 'xyz', group: 'B Team', image: ''});
}
search(queryTxt: string): Observable<Staff[]> {
return Observable.of(this.staff).map(o => this.staff);
}
refine(refiner: Refiner): Observable<Staff[]> {
return ;
}
}
This is how the service is provided (app.module.ts)
providers: [
{
provide: 'ISDDataService',
useClass: AppService
}
],
The skeleton module also has the results component which uses the data source to query the data
#Component({
selector: 'app-search-results',
templateUrl: './search-results.component.html',
styleUrls: ['./search-results.component.css']
})
export class SearchResultsComponent implements OnInit {
private results: Observable<Staff[]>;
private searchField: FormControl;
constructor(#Inject('ISDDataService') private service: ISDDataService) { }
ngOnInit() {
this.searchField = new FormControl();
this.results = this.searchField.valueChanges
.debounceTime(400)
.distinctUntilChanged()
.switchMap( term => this.service.search(term));
}
}
This set up works like a charm, so proceed to package up, create a tarball and create a new "test" app so I can import the module using npm install (all these steps as per the blog post). So far so good, no errors installing the module.
the test app is just an exact replica of what I used when building the library. Same AppServices inheriting the ISDDataService, same way of providing the service and etc. I try bulding it and it all goes to hell. The error couldn't be more bizarre
ERROR in src/app/app.service.ts(9,14): error TS2420: Class 'AppService' incorrectly implements interface 'ISDDataService'.
Types of property 'refiners' are incompatible.
Type 'Subject<Refiner[]>' is not assignable to type 'Subject<Refiner[]>'. Two different types with this name exist, but they are unrelated.
Types of property 'lift' are incompatible.
Type '<R>(operator: Operator<Refiner[], R>) => Observable<R>' is not assignable to type '<R>(operator: Operator<Refiner[], R>) => Observable<R>'. Two different types with this name exist, but they are unrelated.
Types of parameters 'operator' and 'operator' are incompatible.
Type 'Operator<Refiner[], R>' is not assignable to type 'Operator<Refiner[], R>'. Two different types with this name exist, but they are unrelated.
Types of property 'call' are incompatible.
Type '(subscriber: Subscriber<R>, source: any) => TeardownLogic' is not assignable to type '(subscriber: Subscriber<R>, source: any) => TeardownLogic'. Two different types with this name exist, but they are unrelated.
Types of parameters 'subscriber' and 'subscriber' are incompatible.
Type 'Subscriber<R>' is not assignable to type 'Subscriber<R>'. Two different types with this name exist,
but they are unrelated.
Property 'isStopped' is protected but type 'Subscriber<T>' is not a class derived from 'Subscriber<T>'.
How's something like this "Subject<Refiner[]>' is not assignable to type 'Subject<Refiner[]>'" make sense!!??
I've made a couple of changes here and there but nothing works
Note, this issue is not for the refiner property only. If I remove that, it'll cascade down to the functions and so.
I'm starting to think that perhaps this approach isn't the right one... and here I thought it was pretty clean
anyhow, if anyone can give a hand would be greatly appreciated

Resources