Try to create the app from scratch on Microsoft App domain.
2
.gitignore
vendored
|
@ -1,5 +1,5 @@
|
|||
node_modules
|
||||
/deploy/default.gbui/build
|
||||
/packages/default.gbui/build
|
||||
/dist
|
||||
/guaribas.sqlite
|
||||
/guaribas.log
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
node_modules
|
||||
/deploy/default.gbui/build
|
||||
/packages/default.gbui/build
|
||||
/guaribas.sqlite
|
||||
/guaribas.log
|
||||
/work
|
|
@ -29,7 +29,7 @@ Package Quick Reference
|
|||
------------
|
||||
|Whatsapp|Web|Core|KB|
|
||||
|----|-----|----|----|
|
||||
|[whatsapp.gblib](https://github.com/pragmatismo-io/BotServer/tree/master/deploy/whatsapp.gblib)|[default.gbui](https://github.com/pragmatismo-io/BotServer/tree/master/deploy/default.gbui)|[core.gbapp](https://github.com/pragmatismo-io/BotServer/tree/master/deploy/core.gbapp)|[kb.gbapp](https://github.com/pragmatismo-io/BotServer/tree/master/deploy/kb.gbapp)|
|
||||
|[whatsapp.gblib](https://github.com/pragmatismo-io/BotServer/tree/master/packages/whatsapp.gblib)|[default.gbui](https://github.com/pragmatismo-io/BotServer/tree/master/packages/default.gbui)|[core.gbapp](https://github.com/pragmatismo-io/BotServer/tree/master/packages/core.gbapp)|[kb.gbapp](https://github.com/pragmatismo-io/BotServer/tree/master/packages/kb.gbapp)|
|
||||
|
||||

|
||||
|
||||
|
@ -86,7 +86,7 @@ Note:
|
|||
6. Clone the just forked repository by running `git clone <your-forked-repository-url>/BotServer.git` ;
|
||||
7. Run `npm install -g typescript`;
|
||||
8. Run `npm install` on Command Prompt or PowerShell on the General Bot source-code folder;
|
||||
9. Enter './deploy/default.gbui' folder;
|
||||
9. Enter './packages/default.gbui' folder;
|
||||
10. Run `npm install` folled by `npm run build` (To build default Bot UI);
|
||||
11. Enter the On the downloaded folder (../..);
|
||||
12. Compile the bot server by `tsc`.
|
||||
|
|
|
@ -57,7 +57,7 @@ export class AdminDialog extends IGBDialog {
|
|||
let deployer = new GBDeployer(min.core, importer);
|
||||
await deployer.undeployPackageFromLocalPath(
|
||||
min.instance,
|
||||
UrlJoin("deploy", packageName)
|
||||
UrlJoin("packages", packageName)
|
||||
);
|
||||
}
|
||||
|
|
@ -36,14 +36,17 @@ import { GuaribasAdmin } from "../models/AdminModel";
|
|||
import { IGBCoreService } from "botlib";
|
||||
import { AuthenticationContext, TokenResponse } from "adal-node";
|
||||
const UrlJoin = require("url-join");
|
||||
|
||||
const ngrok = require("ngrok");
|
||||
const msRestAzure = require("ms-rest-azure");
|
||||
const PasswordGenerator = require("strict-password-generator").default;
|
||||
|
||||
export class GBAdminService {
|
||||
static generateUuid(): string {
|
||||
return msRestAzure.generateUuid();
|
||||
}
|
||||
static masterBotInstanceId = 0;
|
||||
|
||||
public static StrongRegex = new RegExp(
|
||||
"^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#\$%\^&\*\+_\-])(?=.{8,})"
|
||||
"^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*+_-])(?=.{8,})"
|
||||
);
|
||||
|
||||
core: IGBCoreService;
|
||||
|
@ -76,6 +79,37 @@ export class GBAdminService {
|
|||
return Promise.resolve(obj.value);
|
||||
}
|
||||
|
||||
public static async acquireMsGraphTokenFromUsername(username, password) {
|
||||
return new Promise<string>(async (resolve, reject) => {
|
||||
let resource = "https://graph.microsoft.com";
|
||||
let authenticatorAuthorityHostUrl = "https://login.microsoftonline.com";
|
||||
let authenticatorTenant = "pragmatismo.onmicrosoft.com";
|
||||
let authenticatorClientId = "0ffice19-91d5-41ea-98a4-ceea1655cc0b";
|
||||
|
||||
let authorizationUrl = UrlJoin(
|
||||
authenticatorAuthorityHostUrl,
|
||||
authenticatorTenant,
|
||||
"/oauth2/authorize"
|
||||
);
|
||||
var authenticationContext = new AuthenticationContext(authorizationUrl);
|
||||
|
||||
authenticationContext.acquireTokenWithUsernamePassword(
|
||||
resource,
|
||||
username,
|
||||
password,
|
||||
authenticatorClientId,
|
||||
async (err, res) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
let token = res as TokenResponse;
|
||||
resolve(token.accessToken);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
public async acquireElevatedToken(instanceId): Promise<string> {
|
||||
return new Promise<string>(async (resolve, reject) => {
|
||||
let instance = await this.core.loadInstanceById(instanceId);
|
||||
|
@ -91,10 +125,9 @@ export class GBAdminService {
|
|||
"/oauth2/authorize"
|
||||
);
|
||||
|
||||
var authenticationContext = new AuthenticationContext(authorizationUrl);
|
||||
let refreshToken = await this.getValue(instanceId, "refreshToken");
|
||||
let resource = "https://graph.microsoft.com";
|
||||
|
||||
var authenticationContext = new AuthenticationContext(authorizationUrl);
|
||||
authenticationContext.acquireTokenWithRefreshToken(
|
||||
refreshToken,
|
||||
instance.authenticatorClientId,
|
||||
|
@ -104,27 +137,65 @@ export class GBAdminService {
|
|||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
let tokens = res as TokenResponse;
|
||||
let token = res as TokenResponse;
|
||||
await this.setValue(
|
||||
instanceId,
|
||||
"accessToken",
|
||||
tokens.accessToken
|
||||
token.accessToken
|
||||
);
|
||||
await this.setValue(
|
||||
instanceId,
|
||||
"refreshToken",
|
||||
tokens.refreshToken
|
||||
token.refreshToken
|
||||
);
|
||||
await this.setValue(
|
||||
instanceId,
|
||||
"expiresOn",
|
||||
tokens.expiresOn.toString()
|
||||
token.expiresOn.toString()
|
||||
);
|
||||
resolve(tokens.accessToken);
|
||||
resolve(token.accessToken);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static async getADALTokenFromUsername(
|
||||
username: string,
|
||||
password: string
|
||||
) {
|
||||
let credentials = await GBAdminService.getADALCredentialsFromUsername(
|
||||
username,
|
||||
password
|
||||
);
|
||||
let accessToken = credentials.tokenCache._entries[0].accessToken;
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
public static async getADALCredentialsFromUsername(
|
||||
username: string,
|
||||
password: string
|
||||
) {
|
||||
let credentials = await msRestAzure.loginWithUsernamePassword(
|
||||
username,
|
||||
password
|
||||
);
|
||||
return credentials;
|
||||
}
|
||||
|
||||
public static getRndPassword() {
|
||||
const passwordGenerator = new PasswordGenerator();
|
||||
const options = {
|
||||
upperCaseAlpha: true,
|
||||
lowerCaseAlpha: true,
|
||||
number: true,
|
||||
specialCharacter: true,
|
||||
minimumLength: 12,
|
||||
maximumLength: 14
|
||||
};
|
||||
let password = passwordGenerator.generatePassword(options);
|
||||
password = password.replace(/[=:;\?]/g, "");
|
||||
return password;
|
||||
}
|
||||
}
|
|
@ -45,15 +45,14 @@ import { SearchManagementClient } from "azure-arm-search";
|
|||
import { WebResource, ServiceClient, HttpMethods } from "ms-rest-js";
|
||||
import * as simplegit from "simple-git/promise";
|
||||
import { AppServicePlan } from "azure-arm-website/lib/models";
|
||||
import { GBConfigService } from "../../../deploy/core.gbapp/services/GBConfigService";
|
||||
import { GBConfigService } from "../../../packages/core.gbapp/services/GBConfigService";
|
||||
import { GBAdminService } from "../../../packages/admin.gbapp/services/GBAdminService";
|
||||
|
||||
const Spinner = require("cli-spinner").Spinner;
|
||||
const scanf = require("scanf");
|
||||
const msRestAzure = require("ms-rest-azure");
|
||||
const git = simplegit();
|
||||
const logger = require("../../../src/logger");
|
||||
const UrlJoin = require("url-join");
|
||||
const PasswordGenerator = require("strict-password-generator").default;
|
||||
const iconUrl =
|
||||
"https://github.com/pragmatismo-io/BotServer/blob/master/docs/images/generalbots-logo-squared.png";
|
||||
const publicIp = require("public-ip");
|
||||
|
@ -92,6 +91,9 @@ export class AzureDeployerService extends GBService {
|
|||
let keys: any;
|
||||
let name = instance.botId;
|
||||
|
||||
instance.marketplacePassword = GBAdminService.getRndPassword();
|
||||
await this.internalDeployApp(name, instance.marketplacePassword)
|
||||
|
||||
logger.info(`Deploying Deploy Group (It may take a few minutes)...`);
|
||||
await this.createDeployGroup(name, instance.cloudLocation);
|
||||
|
||||
|
@ -108,8 +110,8 @@ export class AzureDeployerService extends GBService {
|
|||
instance.cloudLocation
|
||||
);
|
||||
|
||||
let administratorLogin = AzureDeployerService.getRndAdminAccount();
|
||||
let administratorPassword = AzureDeployerService.getRndPassword();
|
||||
let administratorLogin = `sa${GBAdminService.getRndPassword()}`;
|
||||
let administratorPassword = GBAdminService.getRndPassword();
|
||||
|
||||
logger.info(`Deploying Bot Storage...`);
|
||||
let storageServer = `${name}-storage-server`;
|
||||
|
@ -193,7 +195,7 @@ export class AzureDeployerService extends GBService {
|
|||
culture,
|
||||
instance.nlpAuthoringKey
|
||||
);
|
||||
let appId = msRestAzure.generateUuid();
|
||||
let appId = GBAdminService.generateUuid();
|
||||
instance.nlpEndpoint = nlp.endpoint;
|
||||
instance.nlpKey = keys.key1;
|
||||
instance.nlpAppId = nlpAppId;
|
||||
|
@ -218,19 +220,18 @@ export class AzureDeployerService extends GBService {
|
|||
let password = GBConfigService.get("CLOUD_PASSWORD");
|
||||
let subscriptionId = GBConfigService.get("CLOUD_SUBSCRIPTIONID");
|
||||
|
||||
let credentials = await msRestAzure.loginWithUsernamePassword(
|
||||
let credentials = await GBAdminService.getADALCredentialsFromUsername(
|
||||
username,
|
||||
password
|
||||
);
|
||||
let storageClient = new SqlManagementClient(credentials, subscriptionId);
|
||||
|
||||
let ip = await publicIp.v4();
|
||||
|
||||
let params = {
|
||||
startIpAddress: ip,
|
||||
endIpAddress: ip
|
||||
};
|
||||
|
||||
let storageClient = new SqlManagementClient(credentials, subscriptionId);
|
||||
await storageClient.firewallRules.createOrUpdate(
|
||||
groupName,
|
||||
serverName,
|
||||
|
@ -298,7 +299,7 @@ export class AzureDeployerService extends GBService {
|
|||
|
||||
// Connects to the cloud and retrives subscriptions.
|
||||
|
||||
let credentials = await msRestAzure.loginWithUsernamePassword(
|
||||
let credentials = await GBAdminService.getADALCredentialsFromUsername(
|
||||
username,
|
||||
password
|
||||
);
|
||||
|
@ -342,7 +343,7 @@ export class AzureDeployerService extends GBService {
|
|||
instance.cloudSubscriptionId = subscriptionId;
|
||||
instance.cloudLocation = location;
|
||||
instance.nlpAuthoringKey = authoringKey;
|
||||
instance.adminPass = AzureDeployerService.getRndPassword();
|
||||
instance.adminPass = GBAdminService.getRndPassword();
|
||||
|
||||
this.resourceClient = new ResourceManagementClient.default(
|
||||
credentials,
|
||||
|
@ -423,13 +424,46 @@ export class AzureDeployerService extends GBService {
|
|||
req.headers = {};
|
||||
req.headers["Content-Type"] = "application/json; charset=utf-8";
|
||||
req.headers["accept-language"] = "*";
|
||||
req.headers["x-ms-client-request-id"] = msRestAzure.generateUuid();
|
||||
req.headers["x-ms-client-request-id"] = GBAdminService.generateUuid();
|
||||
req.headers["Authorization"] = "Bearer " + accessToken;
|
||||
|
||||
let httpClient = new ServiceClient();
|
||||
let res = await httpClient.sendRequest(req);
|
||||
}
|
||||
|
||||
private async internalDeployApp(name, pass) {
|
||||
|
||||
let username = GBConfigService.get("CLOUD_USERNAME");
|
||||
let password = GBConfigService.get("CLOUD_PASSWORD");
|
||||
let accessToken = await GBAdminService.acquireMsGraphTokenFromUsername(username, password);
|
||||
|
||||
let graphUrl = "https://graph.microsoft.com";
|
||||
let expiresOn = new Date().toISOString();
|
||||
|
||||
let parameters = {
|
||||
displayName: name,
|
||||
passwordCredentials: [
|
||||
{
|
||||
secretText: pass,
|
||||
endDateTime: expiresOn
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
let req = new WebResource();
|
||||
req.method = "POST";
|
||||
req.url = `${graphUrl}/beta/applications`;
|
||||
req.headers = {};
|
||||
req.headers["Content-Type"] = "application/json; charset=utf-8";
|
||||
req.headers["accept-language"] = "*";
|
||||
req.headers["x-ms-client-request-id"] = GBAdminService.generateUuid();
|
||||
req.headers["Authorization"] = "Bearer " + accessToken;
|
||||
req.body = parameters;
|
||||
|
||||
let httpClient = new ServiceClient();
|
||||
return await httpClient.sendRequest(req);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://github.com/Azure/azure-rest-api-specs/blob/master/specification/botservice/resource-manager/Microsoft.BotService/preview/2017-12-01/botservice.json
|
||||
*/
|
||||
|
@ -451,7 +485,7 @@ export class AzureDeployerService extends GBService {
|
|||
let baseUrl = `https://management.azure.com/`;
|
||||
await this.registerProviders(subscriptionId, baseUrl, accessToken);
|
||||
|
||||
let appPassword = AzureDeployerService.getRndPassword();
|
||||
let appPassword = GBAdminService.getRndPassword();
|
||||
|
||||
let parameters = {
|
||||
location: location,
|
||||
|
@ -459,7 +493,7 @@ export class AzureDeployerService extends GBService {
|
|||
name: "F0"
|
||||
},
|
||||
name: botId,
|
||||
kind: "sdk",
|
||||
kind: "bot",
|
||||
properties: {
|
||||
description: description,
|
||||
displayName: name,
|
||||
|
@ -468,12 +502,13 @@ export class AzureDeployerService extends GBService {
|
|||
luisAppIds: [nlpAppId],
|
||||
luisKey: nlpKey,
|
||||
msaAppId: appId,
|
||||
msaAppPassword: appPassword
|
||||
msaAppPassword: appPassword,
|
||||
enabledChannels: ["webchat", "skype", "facebook"],
|
||||
configuredChannels: ["webchat", "skype", "facebook"]
|
||||
}
|
||||
};
|
||||
|
||||
let httpClient = new ServiceClient();
|
||||
|
||||
let query = `subscriptions/${subscriptionId}/resourceGroups/${group}/providers/${
|
||||
this.provider
|
||||
}/botServices/${botId}?api-version=${AzureDeployerService.apiVersion}`;
|
||||
|
@ -526,10 +561,8 @@ export class AzureDeployerService extends GBService {
|
|||
let password = GBConfigService.get("CLOUD_PASSWORD");
|
||||
let subscriptionId = GBConfigService.get("CLOUD_SUBSCRIPTIONID");
|
||||
|
||||
let credentials = await msRestAzure.loginWithUsernamePassword(
|
||||
username,
|
||||
password
|
||||
);
|
||||
let accessToken = await GBAdminService.getADALTokenFromUsername(username, password);
|
||||
let httpClient = new ServiceClient();
|
||||
|
||||
let parameters = {
|
||||
properties: {
|
||||
|
@ -537,9 +570,6 @@ export class AzureDeployerService extends GBService {
|
|||
}
|
||||
};
|
||||
|
||||
let accessToken = credentials.tokenCache._entries[0].accessToken;
|
||||
let httpClient = new ServiceClient();
|
||||
|
||||
let query = `subscriptions/${subscriptionId}/resourceGroups/${group}/providers/${
|
||||
this.provider
|
||||
}/botServices/${botId}?api-version=${AzureDeployerService.apiVersion}`;
|
||||
|
@ -763,6 +793,9 @@ export class AzureDeployerService extends GBService {
|
|||
numberOfWorkers: 1,
|
||||
phpVersion: "5.5"
|
||||
};
|
||||
|
||||
// TODO: Copy .env to app settings.
|
||||
|
||||
return this.webSiteClient.webApps.createOrUpdateConfiguration(
|
||||
group,
|
||||
name,
|
||||
|
@ -770,41 +803,9 @@ export class AzureDeployerService extends GBService {
|
|||
);
|
||||
}
|
||||
|
||||
private deleteDeploy(name) {
|
||||
return this.resourceClient.resourceGroups.deleteMethod(name);
|
||||
}
|
||||
|
||||
async deployGeneralBotsToAzure() {
|
||||
let status = await git.status();
|
||||
}
|
||||
|
||||
private static getRndAdminAccount() {
|
||||
const passwordGenerator = new PasswordGenerator();
|
||||
const options = {
|
||||
upperCaseAlpha: false,
|
||||
lowerCaseAlpha: true,
|
||||
number: true,
|
||||
specialCharacter: false,
|
||||
minimumLength: 8,
|
||||
maximumLength: 8
|
||||
};
|
||||
let generated = passwordGenerator.generatePassword(options);
|
||||
return `sa${generated}`;
|
||||
}
|
||||
|
||||
private static getRndPassword() {
|
||||
const passwordGenerator = new PasswordGenerator();
|
||||
const options = {
|
||||
upperCaseAlpha: true,
|
||||
lowerCaseAlpha: true,
|
||||
number: true,
|
||||
specialCharacter: true,
|
||||
minimumLength: 12,
|
||||
maximumLength: 14
|
||||
};
|
||||
let password = passwordGenerator.generatePassword(options);
|
||||
password = password.replace(/[=:;\?]/g, "");
|
||||
return password;
|
||||
// TODO: Copy github to webapp.
|
||||
}
|
||||
|
||||
static getKBSearchSchema(indexName) {
|
|
@ -52,12 +52,9 @@ import { AzureDeployerService } from "../../azuredeployer.gbapp/services/AzureDe
|
|||
/** Deployer service for bots, themes, ai and more. */
|
||||
export class GBDeployer {
|
||||
core: IGBCoreService;
|
||||
|
||||
importer: GBImporter;
|
||||
|
||||
workDir: string = "./work";
|
||||
|
||||
static deployFolder = "deploy";
|
||||
static deployFolder = "packages";
|
||||
|
||||
constructor(core: IGBCoreService, importer: GBImporter) {
|
||||
this.core = core;
|
||||
|
@ -123,7 +120,7 @@ export class GBDeployer {
|
|||
|
||||
gbappPackages.forEach(e => {
|
||||
// Skips .gbapp inside deploy folder.
|
||||
if (!e.startsWith("deploy")) {
|
||||
if (!e.startsWith("packages")) {
|
||||
logger.info(`Deploying app: ${e}...`);
|
||||
import(e)
|
||||
.then(m => {
|
||||
|
@ -374,7 +371,7 @@ export class GBDeployer {
|
|||
*
|
||||
*/
|
||||
async scanBootPackage() {
|
||||
const deployFolder = "deploy";
|
||||
const deployFolder = "packages";
|
||||
let bootPackage = GBConfigService.get("BOOT_PACKAGE");
|
||||
|
||||
if (bootPackage === "none") {
|
Before Width: | Height: | Size: 693 B After Width: | Height: | Size: 693 B |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.5 KiB |
32
src/app.ts
|
@ -37,22 +37,22 @@ const logger = require("./logger");
|
|||
const express = require("express");
|
||||
const bodyParser = require("body-parser");
|
||||
|
||||
import { GBConfigService } from "../deploy/core.gbapp/services/GBConfigService";
|
||||
import { GBConversationalService } from "../deploy/core.gbapp/services/GBConversationalService";
|
||||
import { GBMinService } from "../deploy/core.gbapp/services/GBMinService";
|
||||
import { GBDeployer } from "../deploy/core.gbapp/services/GBDeployer";
|
||||
import { GBWhatsappPackage } from "./../deploy/whatsapp.gblib/index";
|
||||
import { GBCoreService } from "../deploy/core.gbapp/services/GBCoreService";
|
||||
import { GBImporter } from "../deploy/core.gbapp/services/GBImporter";
|
||||
import { GBAnalyticsPackage } from "../deploy/analytics.gblib";
|
||||
import { GBCorePackage } from "../deploy/core.gbapp";
|
||||
import { GBKBPackage } from "../deploy/kb.gbapp";
|
||||
import { GBSecurityPackage } from "../deploy/security.gblib";
|
||||
import { GBAdminPackage } from "../deploy/admin.gbapp/index";
|
||||
import { GBCustomerSatisfactionPackage } from "../deploy/customer-satisfaction.gbapp";
|
||||
import { GBAdminService } from "../deploy/admin.gbapp/services/GBAdminService";
|
||||
import { GuaribasInstance } from "../deploy/core.gbapp/models/GBModel";
|
||||
import { AzureDeployerService } from "../deploy/azuredeployer.gbapp/services/AzureDeployerService";
|
||||
import { GBConfigService } from "../packages/core.gbapp/services/GBConfigService";
|
||||
import { GBConversationalService } from "../packages/core.gbapp/services/GBConversationalService";
|
||||
import { GBMinService } from "../packages/core.gbapp/services/GBMinService";
|
||||
import { GBDeployer } from "../packages/core.gbapp/services/GBDeployer";
|
||||
import { GBWhatsappPackage } from "./../packages/whatsapp.gblib/index";
|
||||
import { GBCoreService } from "../packages/core.gbapp/services/GBCoreService";
|
||||
import { GBImporter } from "../packages/core.gbapp/services/GBImporter";
|
||||
import { GBAnalyticsPackage } from "../packages/analytics.gblib";
|
||||
import { GBCorePackage } from "../packages/core.gbapp";
|
||||
import { GBKBPackage } from "../packages/kb.gbapp";
|
||||
import { GBSecurityPackage } from "../packages/security.gblib";
|
||||
import { GBAdminPackage } from "../packages/admin.gbapp/index";
|
||||
import { GBCustomerSatisfactionPackage } from "../packages/customer-satisfaction.gbapp";
|
||||
import { GBAdminService } from "../packages/admin.gbapp/services/GBAdminService";
|
||||
import { GuaribasInstance } from "../packages/core.gbapp/models/GBModel";
|
||||
import { AzureDeployerService } from "../packages/azuredeployer.gbapp/services/AzureDeployerService";
|
||||
import { IGBPackage, IGBInstance } from "botlib";
|
||||
|
||||
let appPackages = new Array<IGBPackage>();
|
||||
|
|
|
@ -22,8 +22,8 @@
|
|||
"include": [
|
||||
"test/**/*",
|
||||
"src/**/*",
|
||||
"deploy/*.gbapp/**/*",
|
||||
"deploy/*.gblib/**/*"
|
||||
"packages/*.gbapp/**/*",
|
||||
"packages/*.gblib/**/*"
|
||||
],
|
||||
"exclude": ["dist", "node_modules"]
|
||||
}
|
||||
|
|