Files
platformclient/ts/classes.platformclient.ts
T

235 lines
7.9 KiB
TypeScript

import { SzEmailConnector } from './email/classes.emailconnector.js';
import { SzSmsConnector } from './email/classes.smsconnector.js';
import { SzPushNotificationConnector } from './email/classes.pushnotificationconnector.js';
import { SzLetterConnector } from './email/classes.letterconnector.js';
import * as plugins from './plugins.js';
export interface ISzPlatformClientOptions {
authorizationString?: string;
authorization?: string;
token?: string;
url?: string;
platformUrl?: string;
binding?: plugins.servezoneInterfaces.platform.IPlatformBinding;
bindings?: plugins.servezoneInterfaces.platform.IPlatformBinding[];
}
export class SzPlatformClient {
public debugMode = false;
private authorizationString?: string;
private connectionAddress?: string;
public platformBindings: plugins.servezoneInterfaces.platform.IPlatformBinding[] = [];
public typedrouter: plugins.typedrequest.TypedRouter = new plugins.typedrequest.TypedRouter();
public typedsocket!: plugins.typedsocket.TypedSocket;
private qenvInstance = new plugins.qenv.Qenv();
public emailConnector = new SzEmailConnector(this);
public smsConnector = new SzSmsConnector(this);
public pushNotificationConnector = new SzPushNotificationConnector(this);
public letterConnector = new SzLetterConnector(this);
constructor(authorizationStringArg?: string | ISzPlatformClientOptions) {
this.applyOptions(authorizationStringArg);
}
public async init(authorizationStringArg?: string | ISzPlatformClientOptions) {
this.applyOptions(authorizationStringArg);
if (!this.authorizationString) {
this.authorizationString = await this.getConfiguredAuthorizationString();
}
if (this.authorizationString === 'test') {
this.activateDebugMode();
return;
}
this.platformBindings = this.mergePlatformBindings(
this.platformBindings,
await this.discoverPlatformBindings()
);
if (!this.authorizationString) {
this.authorizationString = this.getAuthorizationStringFromBindings();
}
if (!this.authorizationString) throw new Error('authorizationString is required');
if (this.authorizationString === 'test') {
this.activateDebugMode();
return;
}
this.typedsocket = await plugins.typedsocket.TypedSocket.createClient(
this.typedrouter as any,
await this.getConnectionAddress()
);
await this.setAuthorizationTag();
}
private activateDebugMode() {
this.debugMode = true;
console.log('debug mode activated.');
}
public getPlatformBinding(
capabilityArg?: plugins.servezoneInterfaces.platform.TPlatformCapability
) {
return this.platformBindings.find((bindingArg) => {
return (
bindingArg.desiredState !== 'disabled' &&
bindingArg.status !== 'failed' &&
(!capabilityArg || bindingArg.capability === capabilityArg)
);
});
}
private applyOptions(optionsArg?: string | ISzPlatformClientOptions) {
if (!optionsArg) {
return;
}
if (typeof optionsArg === 'string') {
this.authorizationString = optionsArg;
return;
}
this.authorizationString =
optionsArg.authorizationString ||
optionsArg.authorization ||
optionsArg.token ||
this.authorizationString;
this.connectionAddress = optionsArg.url || optionsArg.platformUrl || this.connectionAddress;
this.platformBindings = this.mergePlatformBindings(
this.platformBindings,
[optionsArg.binding, ...(optionsArg.bindings || [])].filter(
Boolean
) as plugins.servezoneInterfaces.platform.IPlatformBinding[]
);
}
private async getConnectionAddress() {
const connectionAddress =
this.connectionAddress ||
(await this.getConfiguredEnvVar('SERVEZONE_PLATFORM_URL')) ||
this.getConnectionAddressFromBindings();
if (!connectionAddress) throw new Error('SERVEZONE_PLATFORM_URL or platform binding endpoint is required');
return connectionAddress;
}
private getConnectionAddressFromBindings() {
for (const binding of this.platformBindings) {
if (binding.desiredState === 'disabled' || binding.status === 'failed') {
continue;
}
if (!this.isSupportedConnectorCapability(binding.capability)) {
continue;
}
const endpoint = binding.endpoints?.find((endpointArg) => {
return endpointArg.protocol === 'typedrequest' || endpointArg.protocol === 'http';
});
const endpointUrl = endpoint?.internalUrl || endpoint?.externalUrl;
if (endpointUrl) {
return endpointUrl;
}
}
}
private isSupportedConnectorCapability(
capabilityArg: plugins.servezoneInterfaces.platform.TPlatformCapability
) {
return ['email', 'sms', 'pushnotification', 'letter'].includes(capabilityArg);
}
private async getConfiguredAuthorizationString() {
return (
(await this.getConfiguredEnvVar('SERVEZONE_PLATFORM_AUTHORIZATION')) ||
(await this.getConfiguredEnvVar('SERVEZONE_PLATFORM_TOKEN'))
);
}
private getAuthorizationStringFromBindings() {
const authEnvNames = [
'SERVEZONE_PLATFORM_AUTHORIZATION',
'SERVEZONE_PLATFORM_TOKEN',
'SERVEZONE_API_TOKEN',
'AUTHORIZATION',
'TOKEN',
];
for (const binding of this.platformBindings) {
for (const credential of binding.credentials || []) {
for (const envName of authEnvNames) {
const value = credential.env?.[envName];
if (value) {
return value;
}
}
}
}
}
private async setAuthorizationTag() {
if (!this.authorizationString) {
return;
}
try {
await this.typedsocket.setTag('authorization' as any, this.authorizationString);
} catch (error) {
if (await this.getConfiguredEnvVar('SERVEZONE_PLATFORMCLIENT_DEBUG')) {
console.warn('Could not set platform authorization tag:', (error as Error).message);
}
}
}
private async discoverPlatformBindings() {
const bindings: plugins.servezoneInterfaces.platform.IPlatformBinding[] = [];
const envBindings = await this.getConfiguredEnvVar('SERVEZONE_PLATFORM_BINDINGS');
const envBinding = await this.getConfiguredEnvVar('SERVEZONE_PLATFORM_BINDING');
if (envBindings) {
bindings.push(...this.parsePlatformBindingsEnv('SERVEZONE_PLATFORM_BINDINGS', envBindings));
}
if (envBinding) {
bindings.push(...this.parsePlatformBindingsEnv('SERVEZONE_PLATFORM_BINDING', envBinding));
}
return bindings;
}
private parsePlatformBindingsEnv(envNameArg: string, envValueArg: string) {
let parsedValue: unknown;
try {
parsedValue = JSON.parse(envValueArg);
} catch (error) {
throw new Error(`${envNameArg} must contain valid JSON`);
}
if (Array.isArray(parsedValue)) {
return parsedValue as plugins.servezoneInterfaces.platform.IPlatformBinding[];
}
if (parsedValue && typeof parsedValue === 'object') {
return [parsedValue as plugins.servezoneInterfaces.platform.IPlatformBinding];
}
throw new Error(`${envNameArg} must contain a platform binding object or array`);
}
private mergePlatformBindings(
existingBindingsArg: plugins.servezoneInterfaces.platform.IPlatformBinding[],
newBindingsArg: plugins.servezoneInterfaces.platform.IPlatformBinding[]
) {
const bindingMap = new Map<string, plugins.servezoneInterfaces.platform.IPlatformBinding>();
for (const binding of [...existingBindingsArg, ...newBindingsArg]) {
bindingMap.set(binding.id, binding);
}
return Array.from(bindingMap.values());
}
private async getConfiguredEnvVar(envNameArg: string) {
const processValue = this.getProcessEnvVar(envNameArg);
if (processValue) {
return processValue;
}
return this.qenvInstance.getEnvVarOnDemand(envNameArg);
}
private getProcessEnvVar(envNameArg: string) {
const processEnv = (globalThis as typeof globalThis & {
process?: { env?: Record<string, string | undefined> };
}).process?.env;
return processEnv?.[envNameArg];
}
}