feat: add platform binding runtime config
This commit is contained in:
@@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@serve.zone/platformclient',
|
||||
version: '1.1.2',
|
||||
version: '1.1.3',
|
||||
description: 'a module that makes it really easy to use the serve.zone platform inside your app'
|
||||
}
|
||||
|
||||
+202
-12
@@ -4,9 +4,21 @@ import { SzPushNotificationConnector } from './email/classes.pushnotificationcon
|
||||
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();
|
||||
@@ -16,31 +28,209 @@ export class SzPlatformClient {
|
||||
public pushNotificationConnector = new SzPushNotificationConnector(this);
|
||||
public letterConnector = new SzLetterConnector(this);
|
||||
|
||||
constructor(authorizationStringArg?: string) {
|
||||
this.authorizationString = authorizationStringArg;
|
||||
constructor(authorizationStringArg?: string | ISzPlatformClientOptions) {
|
||||
this.applyOptions(authorizationStringArg);
|
||||
}
|
||||
|
||||
public async init(authorizationStringArg?: string) {
|
||||
if (authorizationStringArg) {
|
||||
this.authorizationString = 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)
|
||||
this.authorizationString = process.env.SERVEZONE_PLATFROM_AUTHORIZATION;
|
||||
if (!this.authorizationString) throw new Error('authorizationString is required');
|
||||
if (this.authorizationString === 'test') {
|
||||
this.debugMode = true;
|
||||
console.log('debug mode activated.');
|
||||
this.activateDebugMode();
|
||||
return;
|
||||
}
|
||||
this.typedsocket = await plugins.typedsocket.TypedSocket.createClient(
|
||||
this.typedrouter,
|
||||
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 = await this.qenvInstance.getEnvVarOnDemand('SERVEZONE_API_DOMAIN');
|
||||
if (!connectionAddress) throw new Error('SERVEZONE_API_DOMAIN is required');
|
||||
const connectionAddress =
|
||||
this.connectionAddress ||
|
||||
(await this.getConfiguredEnvVar('SERVEZONE_PLATFORM_URL')) ||
|
||||
this.getConnectionAddressFromBindings() ||
|
||||
(await this.getConfiguredEnvVar('SERVEZONE_API_DOMAIN'));
|
||||
if (!connectionAddress) throw new Error('SERVEZONE_PLATFORM_URL or SERVEZONE_API_DOMAIN 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')) ||
|
||||
(await this.getConfiguredEnvVar('SERVEZONE_PLATFROM_AUTHORIZATION'))
|
||||
);
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user