From 3d6bc56eca84542483dcb41c93b3f7bafb890dc6 Mon Sep 17 00:00:00 2001 From: rodrigorodriguez Date: Sun, 29 Jan 2023 12:02:14 -0300 Subject: [PATCH] new(basic.gblib): VBS to JS directly now and minor fixes. --- .travis.yml | 2 +- package.json | 2 +- packages/admin.gbapp/dialogs/AdminDialog.ts | 9 - .../admin.gbapp/services/GBAdminService.ts | 11 +- .../services/AzureDeployerService.ts | 154 ++++++++--------- packages/basic.gblib/services/GBVMService.ts | 67 +++++--- packages/basic.gblib/services/TSCompiler.ts | 102 ------------ .../services/WebAutomationKeywords.ts | 2 +- .../services/vbscript-to-typescript.ts | 156 ------------------ packages/core.gbapp/services/GBDeployer.ts | 104 ++++++------ src/app.ts | 10 +- 11 files changed, 190 insertions(+), 429 deletions(-) delete mode 100644 packages/basic.gblib/services/TSCompiler.ts delete mode 100644 packages/basic.gblib/services/vbscript-to-typescript.ts diff --git a/.travis.yml b/.travis.yml index 79ebe75a..158ca137 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ dist: focal language: node_js node_js: - - 19.4.0 + - 19.5.0 notifications: diff --git a/package.json b/package.json index 74a89de1..0c30eb7d 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "Dário Vieira " ], "engines": { - "node": "=19.4.0" + "node": "=19.5.0" }, "license": "AGPL-3.0", "preferGlobal": true, diff --git a/packages/admin.gbapp/dialogs/AdminDialog.ts b/packages/admin.gbapp/dialogs/AdminDialog.ts index 9edd7a57..19aa3010 100644 --- a/packages/admin.gbapp/dialogs/AdminDialog.ts +++ b/packages/admin.gbapp/dialogs/AdminDialog.ts @@ -312,7 +312,6 @@ export class AdminDialog extends IGBDialog { } await CollectionUtil.asyncForEach(packages, async packageName => { - try { let cmd1; if (packageName.indexOf('.') !== -1) { cmd1 = `deployPackage ${process.env.STORAGE_SITE} /${process.env.STORAGE_LIBRARY}/${botId}.gbai/${packageName}`; @@ -328,14 +327,6 @@ export class AdminDialog extends IGBDialog { } await GBAdminService.deployPackageCommand(min, cmd1, deployer); await min.conversationalService.sendText(min, step, `Finished publishing ${packageName}.`); - } catch (error) { - GBLog.error(error); - if (!skipError) { - await min.conversationalService.sendText(min, step, `ERROR: ${error}`); - - return await step.replaceDialog('/ask', { isReturning: true }); - } - } }); await min.conversationalService.sendText(min, step, Messages[locale].publish_success); if (!step.activeDialog.state.options.confirm) { diff --git a/packages/admin.gbapp/services/GBAdminService.ts b/packages/admin.gbapp/services/GBAdminService.ts index 4afec321..6a8d54b8 100644 --- a/packages/admin.gbapp/services/GBAdminService.ts +++ b/packages/admin.gbapp/services/GBAdminService.ts @@ -37,7 +37,7 @@ 'use strict'; import { AuthenticationContext, TokenResponse } from 'adal-node'; -import { GBMinInstance, IGBAdminService, IGBCoreService, IGBDeployer, IGBInstance } from 'botlib'; +import { GBError, GBLog, GBMinInstance, IGBAdminService, IGBCoreService, IGBDeployer, IGBInstance } from 'botlib'; import { FindOptions } from 'sequelize/types'; import urlJoin from 'url-join'; import { AzureDeployerService } from '../../azuredeployer.gbapp/services/AzureDeployerService.js'; @@ -205,18 +205,23 @@ export class GBAdminService implements IGBAdminService { const options = { where: {} }; options.where = { key: key, instanceId: instanceId }; const obj = await GuaribasAdmin.findOne(options); - return obj.value; } public async acquireElevatedToken(instanceId: number): Promise { const minBoot = GBServer.globals.minBoot; instanceId = minBoot.instance.instanceId; + let expiresOnV; + try { + expiresOnV = await this.getValue(instanceId, 'expiresOn'); + } catch (error) { + throw new Error(`/setupSecurity is required before running /publish.`); + } return new Promise(async (resolve, reject) => { const instance = await this.core.loadInstanceById(instanceId); - const expiresOn = new Date(await this.getValue(instanceId, 'expiresOn')); + const expiresOn = new Date(expiresOnV); if (expiresOn.getTime() > new Date().getTime()) { const accessToken = await this.getValue(instanceId, 'accessToken'); resolve(accessToken); diff --git a/packages/azuredeployer.gbapp/services/AzureDeployerService.ts b/packages/azuredeployer.gbapp/services/AzureDeployerService.ts index 8d8ea6a3..38683641 100644 --- a/packages/azuredeployer.gbapp/services/AzureDeployerService.ts +++ b/packages/azuredeployer.gbapp/services/AzureDeployerService.ts @@ -42,7 +42,7 @@ import { CognitiveServicesManagementClient } from '@azure/arm-cognitiveservices' import { ResourceManagementClient } from '@azure/arm-resources'; import { SubscriptionClient } from '@azure/arm-subscriptions'; import { SearchManagementClient } from '@azure/arm-search'; -import { SqlManagementClient } from '@azure/arm-sql'; +import { Server, SqlManagementClient } from '@azure/arm-sql'; import { WebSiteManagementClient } from '@azure/arm-appservice'; import { AppServicePlan, Site, SiteLogsConfig, SiteSourceControl } from '@azure/arm-appservice'; import { GBLog, IGBInstallationDeployer, IGBInstance, IGBDeployer, IGBCoreService } from 'botlib'; @@ -52,12 +52,10 @@ import { GBConfigService } from '../../../packages/core.gbapp/services/GBConfigS import { GBDeployer } from '../../../packages/core.gbapp/services/GBDeployer.js'; import { Account } from '@azure/arm-cognitiveservices'; import MicrosoftGraph from '@microsoft/microsoft-graph-client'; -import {Spinner} from 'cli-spinner'; +import { Spinner } from 'cli-spinner'; import * as publicIp from 'public-ip'; import { AccessToken, TokenCredential } from '@azure/core-auth'; - - const WebSiteResponseTimeout = 900; const iconUrl = 'https://github.com/pragmatismo-io/BotServer/blob/master/docs/images/generalbots-logo-squared.png'; /** @@ -82,13 +80,11 @@ export class AzureDeployerService implements IGBInstallationDeployer { public core: IGBCoreService; private freeTier: boolean; - - public async runSearch (instance: IGBInstance) { + public async runSearch(instance: IGBInstance) { await this.deployer.rebuildIndex(instance, this.getKBSearchSchema(instance.searchIndex)); } - public static async createInstance (deployer: GBDeployer, freeTier: boolean = true): Promise { - + public static async createInstance(deployer: GBDeployer, freeTier: boolean = true): Promise { const username = GBConfigService.get('CLOUD_USERNAME'); const password = GBConfigService.get('CLOUD_PASSWORD'); const subscriptionId = GBConfigService.get('CLOUD_SUBSCRIPTIONID'); @@ -106,7 +102,7 @@ export class AzureDeployerService implements IGBInstallationDeployer { return service; } - private static createRequestObject (url: string, accessToken: string, verb: HttpMethods, body: string) { + private static createRequestObject(url: string, accessToken: string, verb: HttpMethods, body: string) { const req = new WebResource(); req.method = verb; req.url = url; @@ -118,13 +114,13 @@ export class AzureDeployerService implements IGBInstallationDeployer { return req; } - public async getSubscriptions (credentials) { + public async getSubscriptions(credentials) { const subscriptionClient = new SubscriptionClient(credentials); return subscriptionClient.subscriptions.list(); } - public getKBSearchSchema (indexName: any) { + public getKBSearchSchema(indexName: any) { return { name: indexName, fields: [ @@ -235,7 +231,7 @@ export class AzureDeployerService implements IGBInstallationDeployer { }; } - public async botExists (botId: string) { + public async botExists(botId: string) { const baseUrl = `https://management.azure.com/`; const username = GBConfigService.get('CLOUD_USERNAME'); const password = GBConfigService.get('CLOUD_PASSWORD'); @@ -257,7 +253,7 @@ export class AzureDeployerService implements IGBInstallationDeployer { return !res.parsedBody.valid; } - public async updateBotProxy (botId: string, group: string, endpoint: string) { + public async updateBotProxy(botId: string, group: string, endpoint: string) { const baseUrl = `https://management.azure.com/`; const username = GBConfigService.get('CLOUD_USERNAME'); const password = GBConfigService.get('CLOUD_PASSWORD'); @@ -272,9 +268,7 @@ export class AzureDeployerService implements IGBInstallationDeployer { } }; - const query = `subscriptions/${subscriptionId}/resourceGroups/${group}/providers/${ - this.provider - }/botServices/${botId}?api-version=${this.apiVersion}`; + const query = `subscriptions/${subscriptionId}/resourceGroups/${group}/providers/${this.provider}/botServices/${botId}?api-version=${this.apiVersion}`; const url = urlJoin(baseUrl, query); const req = AzureDeployerService.createRequestObject(url, accessToken, 'PATCH', JSON.stringify(parameters)); const res = await httpClient.sendRequest(req); @@ -285,7 +279,7 @@ export class AzureDeployerService implements IGBInstallationDeployer { GBLog.info(`Bot proxy updated at: ${endpoint}.`); } - public async updateBot (botId: string, group: string, name: string, description: string, endpoint: string) { + public async updateBot(botId: string, group: string, name: string, description: string, endpoint: string) { const baseUrl = `https://management.azure.com/`; const username = GBConfigService.get('CLOUD_USERNAME'); const password = GBConfigService.get('CLOUD_PASSWORD'); @@ -303,9 +297,7 @@ export class AzureDeployerService implements IGBInstallationDeployer { } }; - const query = `subscriptions/${subscriptionId}/resourceGroups/${group}/providers/${ - this.provider - }/botServices/${botId}?api-version=${this.apiVersion}`; + const query = `subscriptions/${subscriptionId}/resourceGroups/${group}/providers/${this.provider}/botServices/${botId}?api-version=${this.apiVersion}`; const url = urlJoin(baseUrl, query); const req = AzureDeployerService.createRequestObject(url, accessToken, 'PATCH', JSON.stringify(parameters)); const res = await httpClient.sendRequest(req); @@ -316,7 +308,7 @@ export class AzureDeployerService implements IGBInstallationDeployer { GBLog.info(`Bot updated at: ${endpoint}.`); } - public async deleteBot (botId: string, group: string) { + public async deleteBot(botId: string, group: string) { const baseUrl = `https://management.azure.com/`; const username = GBConfigService.get('CLOUD_USERNAME'); const password = GBConfigService.get('CLOUD_PASSWORD'); @@ -325,9 +317,7 @@ export class AzureDeployerService implements IGBInstallationDeployer { const accessToken = await GBAdminService.getADALTokenFromUsername(username, password); const httpClient = new ServiceClient(); - const query = `subscriptions/${subscriptionId}/resourceGroups/${group}/providers/${ - this.provider - }/botServices/${botId}?api-version=${this.apiVersion}`; + const query = `subscriptions/${subscriptionId}/resourceGroups/${group}/providers/${this.provider}/botServices/${botId}?api-version=${this.apiVersion}`; const url = urlJoin(baseUrl, query); const req = AzureDeployerService.createRequestObject(url, accessToken, 'DELETE', undefined); const res = await httpClient.sendRequest(req); @@ -338,10 +328,9 @@ export class AzureDeployerService implements IGBInstallationDeployer { GBLog.info(`Bot ${botId} was deleted from the provider.`); } - public async openStorageFirewall (groupName: string, serverName: string) { + public async openStorageFirewall(groupName: string, serverName: string) { const subscriptionId = GBConfigService.get('CLOUD_SUBSCRIPTIONID'); - const ip = await publicIp.publicIpv4(); let params = { startIpAddress: ip, @@ -350,7 +339,7 @@ export class AzureDeployerService implements IGBInstallationDeployer { await this.storageClient.firewallRules.createOrUpdate(groupName, serverName, 'gb', params); } - public async deployFarm ( + public async deployFarm( proxyAddress: string, instance: IGBInstance, credentials: any, @@ -474,7 +463,7 @@ export class AzureDeployerService implements IGBInstallationDeployer { return instance; } - public async deployToCloud ( + public async deployToCloud( title: string, username: string, password: string, @@ -505,13 +494,13 @@ export class AzureDeployerService implements IGBInstallationDeployer { /** * @see https://github.com/Azure/azure-rest-api-specs/blob/master/specification/botservice/resource-manager/Microsoft.BotService/preview/2017-12-01/botservice.json */ - public async internalDeployBot ( + public async internalDeployBot( instance, accessToken: string, botId: string, name: string, group, - description: string , + description: string, endpoint, location, nlpAppId, @@ -550,9 +539,7 @@ export class AzureDeployerService implements IGBInstallationDeployer { }; const httpClient = new ServiceClient(); - let query = `subscriptions/${subscriptionId}/resourceGroups/${group}/providers/${ - this.provider - }/botServices/${botId}?api-version=${this.apiVersion}`; + let query = `subscriptions/${subscriptionId}/resourceGroups/${group}/providers/${this.provider}/botServices/${botId}?api-version=${this.apiVersion}`; let url = urlJoin(baseUrl, query); let req = AzureDeployerService.createRequestObject(url, accessToken, 'PUT', JSON.stringify(parameters)); const res = await httpClient.sendRequest(req); @@ -564,9 +551,7 @@ export class AzureDeployerService implements IGBInstallationDeployer { try { //tslint:disable-next-line:max-line-length - query = `subscriptions/${subscriptionId}/resourceGroups/${group}/providers/Microsoft.BotService/botServices/${botId}/channels/WebChatChannel/listChannelWithKeys?api-version=${ - this.apiVersion - }`; + query = `subscriptions/${subscriptionId}/resourceGroups/${group}/providers/Microsoft.BotService/botServices/${botId}/channels/WebChatChannel/listChannelWithKeys?api-version=${this.apiVersion}`; url = urlJoin(baseUrl, query); req = AzureDeployerService.createRequestObject(url, accessToken, 'POST', JSON.stringify(parameters)); const resChannel = await httpClient.sendRequest(req); @@ -578,27 +563,24 @@ export class AzureDeployerService implements IGBInstallationDeployer { reject(error); } }); - } - - public async syncBotServerRepository (group: string, name: string) { + } + + public async syncBotServerRepository(group: string, name: string) { await this.webSiteClient.webApps.syncRepository(group, name); } - - public async initServices (accessToken: string, expiresOnTimestamp, subscriptionId: string) { - + + public async initServices(accessToken: string, expiresOnTimestamp, subscriptionId: string) { this.accessToken = accessToken; - class AccessToken2 implements AccessToken - { - public expiresOnTimestamp: number; - public token: string; + class AccessToken2 implements AccessToken { + public expiresOnTimestamp: number; + public token: string; } class StaticAccessToken implements TokenCredential { - public getToken(): Promise { return new Promise(async (resolve, reject) => { const t = new AccessToken2(); - t.token = accessToken; + t.token = accessToken; t.expiresOnTimestamp = expiresOnTimestamp; resolve(t); }); @@ -614,15 +596,30 @@ export class AzureDeployerService implements IGBInstallationDeployer { this.searchClient = new SearchManagementClient(token, subscriptionId); } - private async createStorageServer (group: string, name: string, administratorLogin: string, administratorPassword: string, serverName: string, location: string) { + private async createStorageServer( + group: string, + name: string, + administratorLogin: string, + administratorPassword: string, + serverName: string, + location: string + ) { const params = { location: location, administratorLogin: administratorLogin, administratorLoginPassword: administratorPassword, - fullyQualifiedDomainName: serverName + fullyQualifiedDomainName: serverName, + requestOptions: { timeout: 60 * 1000 * 5 } }; - const database = await this.storageClient.servers.beginCreateOrUpdateAndWait(group, name, params); + let database: Server; + try { + database = await this.storageClient.servers.beginCreateOrUpdateAndWait(group, name, params); + } catch (error) { + // Try again (MSFT issues). + GBLog.info('Storage (server) creation failed. Retrying...'); + database = await this.storageClient.servers.beginCreateOrUpdateAndWait(group, name, params); + } // AllowAllWindowsAzureIps must be created that way, so the Azure Search can // access SQL Database to index its contents. @@ -636,7 +633,7 @@ export class AzureDeployerService implements IGBInstallationDeployer { return database; } - public async createApplication (token: string, name: string) { + public async createApplication(token: string, name: string) { return new Promise((resolve, reject) => { let client = MicrosoftGraph.Client.init({ authProvider: done => { @@ -657,7 +654,7 @@ export class AzureDeployerService implements IGBInstallationDeployer { }); } - public async createApplicationSecret (token: string, appId: string) { + public async createApplicationSecret(token: string, appId: string) { return new Promise((resolve, reject) => { let client = MicrosoftGraph.Client.init({ authProvider: done => { @@ -680,7 +677,7 @@ export class AzureDeployerService implements IGBInstallationDeployer { }); } - private async registerProviders (subscriptionId: string, baseUrl: string, accessToken: string) { + private async registerProviders(subscriptionId: string, baseUrl: string, accessToken: string) { const query = `subscriptions/${subscriptionId}/providers/${this.provider}/register?api-version=2018-02-01`; const requestUrl = urlJoin(baseUrl, query); @@ -693,7 +690,7 @@ export class AzureDeployerService implements IGBInstallationDeployer { (req.headers as any).Authorization = `Bearer ${accessToken}`; } - private async createNLPService ( + private async createNLPService( name: string, description: string, location: string, @@ -731,7 +728,7 @@ export class AzureDeployerService implements IGBInstallationDeployer { return id.replace(/\'/gi, ''); } - private async makeNlpRequest ( + private async makeNlpRequest( location: string, authoringKey: string, body: string, @@ -750,7 +747,7 @@ export class AzureDeployerService implements IGBInstallationDeployer { return await httpClient.sendRequest(req); } - public async refreshEntityList (location: string, nlpAppId: string, clEntityId: string, nlpKey: string, data: any) { + public async refreshEntityList(location: string, nlpAppId: string, clEntityId: string, nlpKey: string, data: any) { const req = new WebResource(); req.method = 'PUT'; req.url = `https://${location}.api.cognitive.microsoft.com/luis/api/v2.0/apps/${nlpAppId}/versions/0.1/closedlists/${clEntityId}`; @@ -763,7 +760,7 @@ export class AzureDeployerService implements IGBInstallationDeployer { return await httpClient.sendRequest(req); } - public async trainNLP (location: string, nlpAppId: string, nlpAuthoringKey: string) { + public async trainNLP(location: string, nlpAppId: string, nlpAuthoringKey: string) { const req = new WebResource(); req.method = 'POST'; req.url = `https://${location}.api.cognitive.microsoft.com/luis/api/v2.0/apps/${nlpAppId}/versions/0.1/train`; @@ -775,7 +772,7 @@ export class AzureDeployerService implements IGBInstallationDeployer { return await httpClient.sendRequest(req); } - public async publishNLP (location: string, nlpAppId: string, nlpAuthoringKey: string) { + public async publishNLP(location: string, nlpAppId: string, nlpAuthoringKey: string) { const body = { versionId: '0.1', isStaging: false, @@ -793,7 +790,7 @@ export class AzureDeployerService implements IGBInstallationDeployer { return await httpClient.sendRequest(req); } - private async createSearch (group: string, name: string, location: string) { + private async createSearch(group: string, name: string, location: string) { const params = { sku: { name: this.freeTier ? 'free' : 'standard' @@ -804,17 +801,26 @@ export class AzureDeployerService implements IGBInstallationDeployer { return await this.searchClient.services.beginCreateOrUpdateAndWait(group, name, params as any); } - private async createStorage (group: string, serverName: string, name: string, location: string) { + private async createStorage(group: string, serverName: string, name: string, location: string) { const params = { - sku: { name: this.freeTier ? 'Free' : 'Basic' }, + sku: { name: 'Basic' }, createMode: 'Default', location: location }; - return await this.storageClient.databases.beginCreateOrUpdateAndWait(group, serverName, name, params); + let database; + try { + database = await this.storageClient.databases.beginCreateOrUpdateAndWait(group, serverName, name, params); + } catch (error) { + + // Try again (MSFT issues). + GBLog.info('Storage (database) creation failed. Retrying...'); + database = await this.storageClient.databases.beginCreateOrUpdateAndWait(group, serverName, name, params); + } + return database; } - private async createCognitiveServices (group: string, name: string, location: string, kind: string): Promise { + private async createCognitiveServices(group: string, name: string, location: string, kind: string): Promise { const params = { sku: { name: name @@ -840,40 +846,40 @@ export class AzureDeployerService implements IGBInstallationDeployer { return await this.cognitiveClient.accounts.beginCreateAndWait(group, name, params); } - private async createSpeech (group: string, name: string, location: string): Promise { + private async createSpeech(group: string, name: string, location: string): Promise { return await this.createCognitiveServices(group, name, location, 'SpeechServices'); } - private async createNLP (group: string, name: string, location: string): Promise { + private async createNLP(group: string, name: string, location: string): Promise { return await this.createCognitiveServices(group, name, location, 'LUIS'); } - private async createNLPAuthoring (group: string, name: string, location: string): Promise { + private async createNLPAuthoring(group: string, name: string, location: string): Promise { return await this.createCognitiveServices(group, name, location, 'LUIS.Authoring'); } - private async createSpellChecker (group: string, name: string): Promise { + private async createSpellChecker(group: string, name: string): Promise { return await this.createCognitiveServices(group, name, 'westus', 'CognitiveServices'); } - private async createTextAnalytics (group: string, name: string, location: string): Promise { + private async createTextAnalytics(group: string, name: string, location: string): Promise { return await this.createCognitiveServices(group, name, location, 'TextAnalytics'); } - private async createDeployGroup (name: string, location: string) { + private async createDeployGroup(name: string, location: string) { const params = { location: location }; return await this.cloud.resourceGroups.createOrUpdate(name, params); } - private async enableResourceProviders (name: string) { + private async enableResourceProviders(name: string) { const ret = await this.cloud.providers.get(name); if (ret.registrationState === 'NotRegistered') { await this.cloud.providers.register(name); } } - private async createHostingPlan (group: string, name: string, location: string): Promise { + private async createHostingPlan(group: string, name: string, location: string): Promise { const params = { serverFarmWithRichSkuName: name, location: location, @@ -887,7 +893,7 @@ export class AzureDeployerService implements IGBInstallationDeployer { return await this.webSiteClient.appServicePlans.beginCreateOrUpdateAndWait(group, name, params); } - private async createServer (farmId: string, group: string, name: string, location: string) { + private async createServer(farmId: string, group: string, name: string, location: string) { let tryed = false; const create = async () => { const parameters: Site = { @@ -937,7 +943,7 @@ export class AzureDeployerService implements IGBInstallationDeployer { } } - private async updateWebisteConfig (group: string, name: string, serverFarmId: string, instance: IGBInstance) { + private async updateWebisteConfig(group: string, name: string, serverFarmId: string, instance: IGBInstance) { const parameters: Site = { location: instance.cloudLocation, serverFarmId: serverFarmId, diff --git a/packages/basic.gblib/services/GBVMService.ts b/packages/basic.gblib/services/GBVMService.ts index a08fdc84..bb04c606 100644 --- a/packages/basic.gblib/services/GBVMService.ts +++ b/packages/basic.gblib/services/GBVMService.ts @@ -36,14 +36,12 @@ import { GBLog, GBMinInstance, GBService, IGBCoreService, GBDialogStep } from 'b import * as Fs from 'fs'; import { GBServer } from '../../../src/app.js'; import { GBDeployer } from '../../core.gbapp/services/GBDeployer.js'; -import { TSCompiler } from './TSCompiler.js'; import { CollectionUtil } from 'pragmatismo-io-framework'; import { ScheduleServices } from './ScheduleServices.js'; import { GBConfigService } from '../../core.gbapp/services/GBConfigService.js'; import urlJoin from 'url-join'; import { NodeVM, VMScript } from 'vm2'; import { createVm2Pool } from './vm2-process/index.js'; -import * as vb2ts from './vbscript-to-typescript.js'; import textract from 'textract'; import walkPromise from 'walk-promise'; import child_process from 'child_process'; @@ -208,21 +206,9 @@ export class GBVMService extends GBService { Fs.writeFileSync(vbsFile, code); Fs.writeFileSync(mapFile, JSON.stringify(jsonMap)); - // Converts VBS into TS. - - vb2ts.convertFile(vbsFile); - - // Convert TS into JS. - - const tsfile: string = `${filename}.ts`; - let tsCode: string = Fs.readFileSync(tsfile, 'utf8'); - Fs.writeFileSync(tsfile, tsCode); - const tsc = new TSCompiler(); - tsc.compile([tsfile]); - // Run JS into the GB context. - const jsfile = `${tsfile}.js`.replace('.ts', ''); + const jsfile: string = `${filename}.js`; if (Fs.existsSync(jsfile)) { let code: string = Fs.readFileSync(jsfile, 'utf8'); @@ -354,12 +340,9 @@ export class GBVMService extends GBService { public async convertGBASICToVBS(min: GBMinInstance, code: string) { // Start and End of VB2TS tags of processing. - code = `<%\n - - ${process.env.ENABLE_AUTH ? `hear gbLogin as login` : ``} - - ${code} - + code = ` + ${process.env.ENABLE_AUTH ? `hear gbLogin as login` : ``} + ${code} `; var allLines = code.split('\n'); @@ -388,6 +371,14 @@ export class GBVMService extends GBService { let keywords = []; let i = 0; + const convertConditions = input => { + var result = input.replace(/ +and +/gi, ' && '); + result = result.replace(/ +or +/gi, ' || '); + result = result.replace(/ +<> +/gi, ' !== '); + result = result.replace(/ += +/gi, ' === '); + return result; + }; + keywords[i++] = [ /^\s*(\w+)\s*\=\s*SELECT\s*(.*)/gim, ($0, $1, $2) => { @@ -397,6 +388,40 @@ export class GBVMService extends GBService { } ]; + keywords[i++] = [ + /if +(.*?) +then/gi, + (input, group1) => { + var condition = convertConditions(group1); + return '\nif (' + condition + ') {\n'; + } + ]; + + keywords[i++] = [/end if/gi, '\n}\n']; + + keywords[i++] = [/else(?!{)/gi, '\n}\nelse {\n']; + + keywords[i++] = [/select case +(.*)/gi, '\nswitch ($1) {\n']; + + keywords[i++] = [/end select/gi, '\n}\n']; + + keywords[i++] = [/function +(.*)\((.*)\)/gi, '\n$1 = ($2) => {\n']; + + keywords[i++] = [/end function/gi, '\n}\n']; + + keywords[i++] = [/for +(.*to.*)/gi, '\nfor ($1) {\n']; + + keywords[i++] = [/^ *next *$/gim, '}\n']; + + keywords[i++] = [ + /do while +(.*)/gi, + function (input, group1) { + var condition = convertConditions(group1); + return '\nwhile (' + condition + ') {\n'; + } + ]; + + keywords[i++] = [/^ *loop *$/gim, '}\n']; + keywords[i++] = [ /^\s*open\s*(.*)/gim, ($0, $1, $2) => { diff --git a/packages/basic.gblib/services/TSCompiler.ts b/packages/basic.gblib/services/TSCompiler.ts deleted file mode 100644 index 572eb0c1..00000000 --- a/packages/basic.gblib/services/TSCompiler.ts +++ /dev/null @@ -1,102 +0,0 @@ -/*****************************************************************************\ -| ( )_ _ | -| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ | -| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ | -| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| (˅) |( (_) ) | -| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' | -| | | ( )_) | | -| (_) \___/' | -| | -| General Bots Copyright (c) Pragmatismo.io. All rights reserved. | -| Licensed under the AGPL-3.0. | -| | -| According to our dual licensing model, this program can be used either | -| under the terms of the GNU Affero General Public License, version 3, | -| or under a proprietary license. | -| | -| The texts of the GNU Affero General Public License with an additional | -| permission and of our proprietary license can be found at and | -| in the LICENSE file you have received along with this program. | -| | -| This program is distributed in the hope that it will be useful, | -| but WITHOUT ANY WARRANTY, without even the implied warranty of | -| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | -| GNU Affero General Public License for more details. | -| | -| "General Bots" is a registered trademark of Pragmatismo.io. | -| The licensing of the program under the AGPLv3 does not imply a | -| trademark license. Therefore any rights, title and interest in | -| our trademarks remain entirely with us. | -| | -\*****************************************************************************/ - -/** - * @fileoverview General Bots server core. - */ - -'use strict'; - -import { GBLog } from 'botlib'; -import ts from 'typescript'; - -/** - * Wrapper for a TypeScript compiler. - */ -export class TSCompiler { - private static shouldIgnoreError (diagnostic) { - const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'); - - if ( - message.indexOf('Cannot find name') >= 0 || - message.indexOf('Cannot find module') >= 0 || - message.indexOf('implicitly has an') >= 0 || - message.indexOf('Cannot invoke an') >= 0 || - message.indexOf('Cannot use imports, exports, or module') >= 0 - ) { - return true; - } - - return false; - } - - public compile ( - fileNames: string[], - options: ts.CompilerOptions = { - noStrictGenericChecks: true, - noImplicitUseStrict: true, - noEmitOnError: false, - noImplicitAny: true, - target: ts.ScriptTarget.ESNext, - module: ts.ModuleKind.None, - moduleResolution: ts.ModuleResolutionKind.Classic, - noEmitHelpers: true, - maxNodeModuleJsDepth: 0, - esModuleInterop: false - } - ) { - const program = ts.createProgram(fileNames, options); - const emitResult = program.emit(); - - const allDiagnostics = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics); - - allDiagnostics.forEach(diagnostic => { - if (!TSCompiler.shouldIgnoreError(diagnostic)) { - const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'); - - if (diagnostic.file !== undefined) { - if ( - diagnostic.file.fileName.indexOf('readable-stream') == -1 && - diagnostic.file.fileName.indexOf('request-promise') == -1 - ) { - const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start); - GBLog.error(`BASIC error: ${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`); - } - } else { - GBLog.error(`BASIC error: ${message}`); - } - } - }); - - return emitResult; - } -} diff --git a/packages/basic.gblib/services/WebAutomationKeywords.ts b/packages/basic.gblib/services/WebAutomationKeywords.ts index 49fad26d..59632ead 100644 --- a/packages/basic.gblib/services/WebAutomationKeywords.ts +++ b/packages/basic.gblib/services/WebAutomationKeywords.ts @@ -145,7 +145,7 @@ export class WebAutomationKeywords { /** * Find element on page DOM. * - * @example GET page,"selector" + * @example GET "selector" */ public async getBySelector ({ handle, selector }) { const page = this.getPageByHandle(handle); diff --git a/packages/basic.gblib/services/vbscript-to-typescript.ts b/packages/basic.gblib/services/vbscript-to-typescript.ts deleted file mode 100644 index 724eb36e..00000000 --- a/packages/basic.gblib/services/vbscript-to-typescript.ts +++ /dev/null @@ -1,156 +0,0 @@ -// Source: https://github.com/uweg/vbscript-to-typescript -'use strict'; - -import fs_1 from 'fs'; -import path from 'path'; - -export function convertFile (file) { - var extension = path.extname(file); - var withoutExtension = file.substr(0, file.length - extension.length); - var targetFile = withoutExtension + '.ts'; - var baseName = path.basename(file, extension); - var content = fs_1.readFileSync(file, 'utf8'); - var result = convert(content, baseName); - console.log('Writing to "' + targetFile + '"...'); - fs_1.writeFileSync(targetFile, result); -} - -export function convert (input, name) { - var result = convertImports(input, name); - return result; -} - -function convertImports (input, name) { - var items = []; - var result = input.replace(//gi, function (input, group1, group2) { - var path = group1 || './'; - var file = '' + path + group2; - items.push({ name: group2, path: file }); - return '<%\n' + group2 + '();\n%>'; - }); - result = convertCode(result); - result = convertExpressions(result); - result = convertStrings(result); - - for (var _i = 0, items_1 = items; _i < items_1.length; _i++) { - var item = items_1[_i]; - result = 'import {' + item.name + '} from "' + item.path + '"\n' + result; - } - return result; -} - -function convertCode (input) { - var result = input.replace(/<%([^=][\s\S]*?)%>/gi, function (input, group1) { - var code = group1; - code = convertComments(code); - code = convertIfStatements(code); - code = convertSwitchStatements(code); - code = convertFunctions(code); - code = convertForStatements(code); - code = convertLoops(code); - code = convertPRec(code); - code = convertPLan(code); - return '<%' + code + '%>'; - }); - return result; -} - -function convertExpressions (input) { - var result = input.replace(/<%=([\s\S]*?)%>/gi, function (input, group1) { - var content = convertPRec(group1); - content = convertPLan(content); - return '${' + content + '}'; - }); - return result; -} - -function convertStrings (input) { - var result = input.replace(/%>([\s\S]+?)<%/gi, '\nResponse.Write(`$1`);\n'); - // Entire document is a string - if (result.indexOf('<%') === -1) { - result = 'Response.Write(`' + result + '`);'; - } - // Start of the document is a string - var firstIndex = result.indexOf('<%'); - if (firstIndex > 0) { - result = 'Response.Write(`' + result.substr(0, firstIndex) + '`);\n' + result.substring(firstIndex + 2); - } - result = result.replace(/%>$/, ''); - // End of the document is a string - var lastIndex = result.lastIndexOf('%>'); - if (lastIndex > -1 && lastIndex < result.length - 2) { - result = result.substr(0, lastIndex) + '\nResponse.Write(`' + result.substr(lastIndex + 3) + '`);'; - } - result = result.replace(/^<%/, ''); - return result; -} - -function convertComments (input) { - var result = ''; - var splitted = input.split(/(".*")/gim); - for (var _i = 0, splitted_1 = splitted; _i < splitted_1.length; _i++) { - var part = splitted_1[_i]; - if (part.indexOf('"') === 0) { - result += part; - } else { - result += part.replace(/'/gi, '//'); - } - } - return result; -} - -function convertIfStatements (input) { - var result = input.replace(/if +(.*?) +then/gi, function (input, group1) { - var condition = convertConditions(group1); - return '\nif (' + condition + ') {\n'; - }); - result = result.replace(/end if/gi, '\n}\n'); - result = result.replace(/else(?!{)/gi, '\n}\nelse {\n'); - return result; -} - -function convertSwitchStatements (input) { - var result = input.replace(/select case +(.*)/gi, '\nswitch ($1) {\n'); - result = result.replace(/end select/gi, '\n}\n'); - return result; -} - -function convertFunctions (input) { - var result = input.replace(/function +(.*)\((.*)\)/gi, '\n$1 = ($2) => {\n'); - result = result.replace(/end function/gi, '\n}\n'); - return result; -} - -function convertForStatements (input) { - var result = input.replace(/for +(.*to.*)/gi, '\nfor ($1) {\n'); - result = result.replace(/^ *next *$/gim, '}\n'); - return result; -} - -function convertConditions (input) { - var result = input.replace(/ +and +/gi, ' && '); - result = result.replace(/ +or +/gi, ' || '); - result = result.replace(/ +<> +/gi, ' !== '); - result = result.replace(/ += +/gi, ' === '); - return result; -} - -function convertLoops (input) { - var result = input.replace(/do while +(.*)/gi, function (input, group1) { - var condition = convertConditions(group1); - return '\nwhile (' + condition + ') {\n'; - }); - - result = result.replace(/^ *loop *$/gim, '}\n'); - return result; -} - -function convertPRec (input) { - var result = input.replace(/(p_rec\("\S+?"\))/gi, '$1.Value'); - return result; -} - -function convertPLan (input) { - var result = input.replace(/(l_\S+?)\(p_lan\)/gi, '$1[p_lan]'); - return result; -} diff --git a/packages/core.gbapp/services/GBDeployer.ts b/packages/core.gbapp/services/GBDeployer.ts index aa7cb0ec..087a3b80 100644 --- a/packages/core.gbapp/services/GBDeployer.ts +++ b/packages/core.gbapp/services/GBDeployer.ts @@ -85,7 +85,7 @@ export class GBDeployer implements IGBDeployer { /** * Deployer needs core and importer to be created. */ - constructor (core: IGBCoreService, importer: GBImporter) { + constructor(core: IGBCoreService, importer: GBImporter) { this.core = core; this.importer = importer; } @@ -94,16 +94,14 @@ export class GBDeployer implements IGBDeployer { * Builds a connection string text to be used in direct * use to database like the Indexer (Azure Search). */ - public static getConnectionStringFromInstance (instance: IGBInstance) { - return `Server=tcp:${instance.storageServer},1433;Database=${instance.storageName};User ID=${ - instance.storageUsername - };Password=${instance.storagePassword};Trusted_Connection=False;Encrypt=True;Connection Timeout=30;`; + public static getConnectionStringFromInstance(instance: IGBInstance) { + return `Server=tcp:${instance.storageServer},1433;Database=${instance.storageName};User ID=${instance.storageUsername};Password=${instance.storagePassword};Trusted_Connection=False;Encrypt=True;Connection Timeout=30;`; } /** * Retrives token and initialize drive client API. */ - public static async internalGetDriveClient (min: GBMinInstance) { + public static async internalGetDriveClient(min: GBMinInstance) { const token = await min.adminService.acquireElevatedToken(min.instance.instanceId); const siteId = process.env.STORAGE_SITE_ID; const libraryId = process.env.STORAGE_LIBRARY; @@ -120,7 +118,7 @@ export class GBDeployer implements IGBDeployer { /** * Performs package deployment in all .gbai or default. */ - public async deployPackages (core: IGBCoreService, server: any, appPackages: IGBPackage[]) { + public async deployPackages(core: IGBCoreService, server: any, appPackages: IGBPackage[]) { // Builds lists of paths to search for packages. let paths = [urlJoin(process.env.PWD, GBDeployer.deployFolder), urlJoin(process.env.PWD, GBDeployer.workFolder)]; @@ -132,7 +130,7 @@ export class GBDeployer implements IGBDeployer { const gbappPackages: string[] = []; const generalPackages: string[] = []; - async function scanPackageDirectory (path) { + async function scanPackageDirectory(path) { // Gets all directories. const isDirectory = source => Fs.lstatSync(source).isDirectory(); @@ -201,7 +199,7 @@ export class GBDeployer implements IGBDeployer { /** * Deploys a new blank bot to the database, cognitive services and other services. */ - public async deployBlankBot (botId: string, mobile: string, email: string) { + public async deployBlankBot(botId: string, mobile: string, email: string) { // Creates a new row on the GuaribasInstance table. const instance = await this.importer.createBotInstance(botId); @@ -243,7 +241,7 @@ export class GBDeployer implements IGBDeployer { /** * Verifies if bot exists on bot catalog. */ - public async botExists (botId: string): Promise { + public async botExists(botId: string): Promise { const service = await AzureDeployerService.createInstance(this); return await service.botExists(botId); @@ -252,7 +250,7 @@ export class GBDeployer implements IGBDeployer { /** * Performs all tasks of deploying a new bot on the cloud. */ - public async deployBotFull (instance: IGBInstance, publicAddress: string): Promise { + public async deployBotFull(instance: IGBInstance, publicAddress: string): Promise { // Reads base configuration from environent file. const service = await AzureDeployerService.createInstance(this); @@ -322,7 +320,7 @@ export class GBDeployer implements IGBDeployer { /** * Performs the NLP publishing process on remote service. */ - public async publishNLP (instance: IGBInstance): Promise { + public async publishNLP(instance: IGBInstance): Promise { const service = await AzureDeployerService.createInstance(this); const res = await service.publishNLP(instance.cloudLocation, instance.nlpAppId, instance.nlpAuthoringKey); if (res.status !== 200 && res.status !== 201) { @@ -333,7 +331,7 @@ export class GBDeployer implements IGBDeployer { /** * Trains NLP on the remote service. */ - public async trainNLP (instance: IGBInstance): Promise { + public async trainNLP(instance: IGBInstance): Promise { const service = await AzureDeployerService.createInstance(this); const res = await service.trainNLP(instance.cloudLocation, instance.nlpAppId, instance.nlpAuthoringKey); if (res.status !== 200 && res.status !== 202) { @@ -350,7 +348,7 @@ export class GBDeployer implements IGBDeployer { /** * Return a zip file for importing bot in apps, currently MS Teams. */ - public async getBotManifest (instance: IGBInstance): Promise { + public async getBotManifest(instance: IGBInstance): Promise { const s = new TeamsService(); const manifest = await s.getManifest( instance.marketplaceId, @@ -367,7 +365,7 @@ export class GBDeployer implements IGBDeployer { /** * Refreshes NLP entities on the remote service. */ - public async refreshNLPEntity (instance: IGBInstance, listName, listData): Promise { + public async refreshNLPEntity(instance: IGBInstance, listName, listData): Promise { const service = await AzureDeployerService.createInstance(this); const res = await service.refreshEntityList( instance.cloudLocation, @@ -384,7 +382,7 @@ export class GBDeployer implements IGBDeployer { /** * Deploys a bot to the storage from a .gbot folder. */ - public async deployBotFromLocalPath (localPath: string, publicAddress: string): Promise { + public async deployBotFromLocalPath(localPath: string, publicAddress: string): Promise { const packageName = Path.basename(localPath); const instance = await this.importer.importIfNotExistsBotPackage(undefined, packageName, localPath); await this.deployBotFull(instance, publicAddress); @@ -393,7 +391,7 @@ export class GBDeployer implements IGBDeployer { /** * Loads all para from tabular file Config.xlsx. */ - public async loadParamsFromTabular (min: GBMinInstance): Promise { + public async loadParamsFromTabular(min: GBMinInstance): Promise { const siteId = process.env.STORAGE_SITE_ID; const libraryId = process.env.STORAGE_LIBRARY; @@ -433,9 +431,7 @@ export class GBDeployer implements IGBDeployer { const results = await client .api( - `https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${libraryId}/drive/items/${ - document[0].id - }/workbook/worksheets('General')/range(address='A7:B100')` + `https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${libraryId}/drive/items/${document[0].id}/workbook/worksheets('General')/range(address='A7:B100')` ) .get(); let index = 0, @@ -453,7 +449,7 @@ export class GBDeployer implements IGBDeployer { /** * Loads all para from tabular file Config.xlsx. */ - public async downloadFolder ( + public async downloadFolder( min: GBMinInstance, localPath: string, remotePath: string, @@ -535,7 +531,7 @@ export class GBDeployer implements IGBDeployer { /** * UndDeploys a bot to the storage. */ - public async undeployBot (botId: string, packageName: string): Promise { + public async undeployBot(botId: string, packageName: string): Promise { // Deletes Bot registration on cloud. const service = await AzureDeployerService.createInstance(this); @@ -556,7 +552,7 @@ export class GBDeployer implements IGBDeployer { /** * Deploys a new package to the database storage (just a group). */ - public async deployPackageToStorage (instanceId: number, packageName: string): Promise { + public async deployPackageToStorage(instanceId: number, packageName: string): Promise { return await GuaribasPackage.create({ packageName: packageName, instanceId: instanceId @@ -566,7 +562,7 @@ export class GBDeployer implements IGBDeployer { /** * Deploys a folder into the bot storage. */ - public async deployPackage (min: GBMinInstance, localPath: string) { + public async deployPackage(min: GBMinInstance, localPath: string) { const packageType = Path.extname(localPath); let handled = false; let pck = null; @@ -575,28 +571,24 @@ export class GBDeployer implements IGBDeployer { const _this = this; await CollectionUtil.asyncForEach(min.appPackages, async (e: IGBPackage) => { - try { - // If it will be handled, create a temporary service layer to be - // called by .gbapp and manage the associated package row. + // If it will be handled, create a temporary service layer to be + // called by .gbapp and manage the associated package row. - if ( - (pck = await e.onExchangeData(min, 'handlePackage', { - name: localPath, - createPackage: async packageName => { - return await _this.deployPackageToStorage(min.instance.instanceId, packageName); - }, - updatePackage: async (p: GuaribasPackage) => { - p.save(); - }, - existsPackage: async (packageName: string) => { - return await _this.getStoragePackageByName(min.instance.instanceId, packageName); - } - })) - ) { - handled = true; - } - } catch (error) { - GBLog.error(error); + if ( + (pck = await e.onExchangeData(min, 'handlePackage', { + name: localPath, + createPackage: async packageName => { + return await _this.deployPackageToStorage(min.instance.instanceId, packageName); + }, + updatePackage: async (p: GuaribasPackage) => { + p.save(); + }, + existsPackage: async (packageName: string) => { + return await _this.getStoragePackageByName(min.instance.instanceId, packageName); + } + })) + ) { + handled = true; } }); @@ -663,16 +655,14 @@ export class GBDeployer implements IGBDeployer { break; default: - const err = GBError.create(`Unhandled package type: ${packageType}.`); - Promise.reject(err); - break; - } + throw GBError.create(`Unhandled package type: ${packageType}.`); +} } /** * Removes the package from the storage and local work folders. */ - public async undeployPackageFromLocalPath (instance: IGBInstance, localPath: string) { + public async undeployPackageFromLocalPath(instance: IGBInstance, localPath: string) { // Gets information about the package. const packageType = Path.extname(localPath); @@ -720,7 +710,7 @@ export class GBDeployer implements IGBDeployer { * Performs automation of the Indexer (Azure Search) and rebuild * its index based on .gbkb structure. */ - public async rebuildIndex (instance: IGBInstance, searchSchema: any) { + public async rebuildIndex(instance: IGBInstance, searchSchema: any) { // Prepares search. const search = new AzureSearch( @@ -770,7 +760,7 @@ export class GBDeployer implements IGBDeployer { /** * Finds a storage package by using package name. */ - public async getStoragePackageByName (instanceId: number, packageName: string): Promise { + public async getStoragePackageByName(instanceId: number, packageName: string): Promise { const where = { packageName: packageName, instanceId: instanceId }; return await GuaribasPackage.findOne({ @@ -782,7 +772,7 @@ export class GBDeployer implements IGBDeployer { * Prepares the React application inside default.gbui folder and * makes this web application available as default web front-end. */ - public setupDefaultGBUI () { + public setupDefaultGBUI() { // Setups paths. const root = 'packages/default.gbui'; @@ -809,7 +799,7 @@ export class GBDeployer implements IGBDeployer { /** * Servers bot storage assets to be used by web, WhatsApp and other channels. */ - public static mountGBKBAssets (packageName: any, botId: string, filename: string) { + public static mountGBKBAssets(packageName: any, botId: string, filename: string) { // Servers menu assets. GBServer.globals.server.use( @@ -848,7 +838,7 @@ export class GBDeployer implements IGBDeployer { /** * Invokes Type Script compiler for a given .gbapp package (Node.js based). */ - public async callGBAppCompiler ( + public async callGBAppCompiler( gbappPath: string, core: IGBCoreService, appPackages: any[] = undefined, @@ -906,7 +896,7 @@ export class GBDeployer implements IGBDeployer { /** * Determines if a given package is of system kind. */ - private isSystemPackage (name: string): Boolean { + private isSystemPackage(name: string): Boolean { const names = [ 'analytics.gblib', 'console.gblib', @@ -930,7 +920,7 @@ export class GBDeployer implements IGBDeployer { /** * Performs the process of compiling all .gbapp folders. */ - private async deployAppPackages (gbappPackages: string[], core: any, appPackages: any[]) { + private async deployAppPackages(gbappPackages: string[], core: any, appPackages: any[]) { // Loops through all ready to load .gbapp packages. let appPackagesProcessed = 0; diff --git a/src/app.ts b/src/app.ts index dd81b2c2..e9b5cb43 100644 --- a/src/app.ts +++ b/src/app.ts @@ -96,9 +96,11 @@ export class GBServer { server.use(bodyParser.urlencoded({ extended: true })); process.on('unhandledRejection', (err, p) => { - console.log('An unhandledRejection occurred'); - console.log(`Rejected Promise: ${p}`); - console.log(`Rejection: ${err}`); + GBLog.error(`UNHANDLED_REJECTION(promises): ${p} ${err.toString()}`); + }); + + process.on('uncaughtException', (err, origin) => { + GBLog.error(`UNCAUGHT_EXCEPTION: ${err.toString()}`); }); // Creates working directory. @@ -240,7 +242,7 @@ export class GBServer { })(); }; - // + // if (process.env.CERTIFICATE_PFX) { const options1 = {