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(); 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 }; }).process?.env; return processEnv?.[envNameArg]; } }