The LivePerson Functions client for NodeJS.
It offers functionality to retrieve all lambdas and invoke them via lambda UUID or event IDs.
Table of Contents:
Capabilities:
- Invoking Lambdas
- Checking if an event is implemented by the account
- Getting lambdas of an account
yarn add liveperson-functions-client
or
npm install liveperson-functions-client
Note: The library exposes typings for IDE assistance/auto-complete and compile time validation for TS projects.
The client will use the OAuth2.0 flow client_credentials
for authorization. Please refer to these docs for further information on that. On each request the client will check if the JWT
is about to expire. If this is the case, the client will try to refresh it. If the JWT
is expired and the client failed to refresh it, an Error
is thrown. The time after which the refreshing logic will kick in can be specified via the property jwtRefreshAfterMinutes
. Alternatively, you can provide your own authorization method that generates a suitable authorization header
by implementing a method that fulfills the GetAuthorizationHeader-Interface:
export type GetAuthorizationHeader = (input: {
url: string;
method: string;
}) => Promise<string>;
Example:
// Default: Provide client id and client secret as auth strategy as follows
import { Client } from 'liveperson-functions-client';
const client = new Client({
accountId: 'myAccountId',
authStrategy: {
clientId: 'myClientId',
clientSecret: 'myClientSecret',
},
});
// Alternative: Provide your own implementation of our type 'GetAuthorizationHeader'
import { Client, GetAuthorizationHeader } from 'liveperson-functions-client';
const getAuthorizationHeader: GetAuthorizationHeader = async ({
url,
method,
}) => {
// example custom implementation
const oauthApiKey = '...';
const oauthApiSecret = '...';
const oauthSignatureMethod = '...';
const oAuth = new OAuth({
consumer: {
key: oauthApiKey,
secret: oauthApiSecret,
},
signature_method: oauthSignatureMethod,
realm: '',
hash_function: (baseString: string, key: string): string => {
return createHmac(oauthSignatureMethod.split('-')[1], key)
.update(baseString)
.digest('base64');
},
});
return oAuth.toHeader(oAuth.authorize({ url, method })).Authorization;
};
const client = new Client({
accountId: 'myAccountId',
authStrategy: getAuthorizationHeader,
});
The client supports Oauth2+DPoP authorization ONLY FOR INTERNAL USE in service-to-service. Required methods can be configured during the initialization as 'authStrategy.' You must provide your implementation of the getAccessTokenInternal
and getDpopHeaderInternal
methods.
Example:
const client = new Client({
accountId: 'myAccountId',
authStrategy: {
getAccessTokenInternal: async (domainUrl: string) => {
// you implementation
return 'accessToken';
},
getDpopHeaderInternal: async (url: string, method: string, accessToken?: string) => {
// you implementation
return 'dopHeader';
},
}
});
While authStrategy and accountId are obligatory parameters for the configuration of the client, multiple other parameters can be set optionally. If you do not set them we default back to our default configuration.
The optional parameters can be found in the interface default config which looks like this.
export interface DefaultConfig {
readonly gwCsdsServiceName?: string;
readonly uiCsdsServiceName?: string;
readonly apiVersion?: string;
readonly timeout?: number;
readonly protocol?: typeof Protocol[keyof typeof Protocol];
readonly getLambdasUri?: string;
readonly invokeUuidUri?: string;
readonly invokeEventUri?: string;
readonly isImplementedUri?: string;
readonly failOnErrorStatusCode?: boolean;
/** Optional HTTP request headers that should be included in CSDS requests. */
readonly csdsHttpHeaders?: { [key: string]: any };
readonly csdsTtlSeconds?: number;
/**
* Time after which the JWT should be refreshed.
*/
readonly jwtRefreshAfterMinutes?: number;
readonly isImplementedCacheDurationInSeconds?: number;
}
// These values default to:
export const defaultConfig: Required<DefaultConfig> = {
gwCsdsServiceName: 'faasGW',
uiCsdsServiceName: 'faasUI',
apiVersion: '1',
timeout: 35000, // ms
protocol: Protocol.HTTPS,
getLambdasUri: 'api/account/%s/lambdas/',
invokeUuidUri: 'api/account/%s/lambdas/%s/invoke',
invokeEventUri: 'api/account/%s/events/%s/invoke',
isImplementedUri: 'api/account/%s/events/%s/isImplemented',
failOnErrorStatusCode: false,
csdsHttpHeaders: {},
csdsTtlSeconds: 600,
jwtRefreshAfterMinutes: 30,
isImplementedCacheDurationInSeconds: 60,
};
If you want to set one of these parameters, just add them to the object passed to the client as its first paramter in the initialization process. Below you can find an example where the optional config param isImplementedCacheDurationInSeconds is set.
const client = new Client({
accountId: 'myAccountId',
authStrategy: {
clientId: 'myClientId',
clientSecret: 'myClientSecret',
},
isImplementedCacheDurationInSeconds: 20;
});
If you want to collect metrics you may implement the interface MetricCollector and pass your implementation to the client when initializing it. The metrics are only held in memory and are not persisted. If you pass no implementation of MetricCollector the metrics will be ignored.
import { Client } from 'liveperson-functions-client';
const client = new Client(
{
accountId: 'myAccountId',
authStrategy: {
clientId: 'myClientId',
clientSecret: 'myClientSecret',
},
},
{
metricCollector: new MyMetricCollector(),
});
const response = await client.invoke({
lambdaUuid: 'uuid',
externalSystem: 'demoSystem',
body: {
headers: [],
payload: {
foo: 'bar',
},
},
});
const response = await client.invoke({
eventId: 'eventId',
externalSystem: 'demoSystem',
body: {
headers: [],
payload: {
foo: 'bar',
},
},
});
const response = await client.isImplemented({
eventId: 'eventId',
externalSystem: 'demoSystem',
});
You have to use your own authentication method when fetching lambdas as it still relies on OAuth 1.0.
const response = await client.getLambdas({
eventId: 'eventId', // filter lambdas for events
state: ['Productive', 'Draft'], // filter lambdas for deployment states
userId: 'userId',
});
Errors with the name FaaSLambdaError
are raised when the invocation fails due to a custom implementation error. The client internally uses verror. We recommend to log the stack
in order to get detailed information about the root cause.
try {
// invoke here
...
} catch (error) {
/**
* LivePerson FunctionsLambdaErrors occur when the lambda fails due to the implementation.
* These exceptions are not relevant for alerting, because there are no issues with the service itself.
*/
if (error.name === "FaaSLambdaError") {
console.info(error.stack, "Error caused by implementation of lambda.");
} else {
console.error(error.stack, "Something unexpected happened.");
}
}
More detailed information on errors that can occur can be found here.