ci: add Jenkinsfile for GitHub pages builds

Resolves: https://github.com/waku-org/js-waku-examples/issues/94

Signed-off-by: Jakub Sokołowski <jakub@status.im>
This commit is contained in:
Jakub Sokołowski 2022-09-06 19:55:29 +02:00
parent 6b5a5dbde0
commit 80efc5ad7c
No known key found for this signature in database
GPG Key ID: 09AA5403E54D9931
10 changed files with 189 additions and 52 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
dist
node_modules
yarn.lock

View File

@ -16,3 +16,10 @@ Here is the list of the examples using [`js-waku`](https://www.npmjs.com/package
- [Using Waku Relay in JavaScript](relay-js): Receive and send text messages with Waku Relay, Use minified bundle from Unpkg.com, JavaScript.
See https://docs.wakuconnect.dev/docs/examples/ for more examples.
# Continuous Integration
The `master` branch is being built by Jenkins CI:
https://ci.infra.status.im/job/website/job/examples.waku.org/
Based on the [`ci/Jenkinsfile`](./ci/Jenkinsfile).

74
ci/Jenkinsfile vendored Normal file
View File

@ -0,0 +1,74 @@
pipeline {
agent { label 'linux' }
options {
disableConcurrentBuilds()
/* manage how many builds we keep */
buildDiscarder(logRotator(
numToKeepStr: '20',
daysToKeepStr: '30',
))
}
environment {
SITE_DOMAIN = 'examples.waku.org'
GIT_AUTHOR_NAME = 'status-im-auto'
GIT_AUTHOR_EMAIL = 'auto@status.im'
PUPPETEER_SKIP_DOWNLOAD = 'true'
}
stages {
stage('Pre') {
steps {
sh 'yarn install --no-lockfile'
/* TODO: Build the main page. */
sh 'mkdir -p build/docs'
}
}
stage('Examples') {
parallel {
stage('eth-pm') { steps { script { buildExample() } } }
stage('relay-angular-chat') { steps { script { buildExample() } } }
stage('relay-reactjs-chat') { steps { script { buildExample() } } }
stage('store-reactjs-chat') { steps { script { buildExample() } } }
stage('web-chat') { steps { script { buildExample() } } }
}
}
stage('HTML Examples') {
parallel {
stage('relay-js') { steps { script { copyExample() } } }
stage('store-js') { steps { script { copyExample() } } }
}
}
stage('Publish') {
//when { expression { GIT_BRANCH.endsWith('master') } }
steps { script {
sh "echo ${SITE_DOMAIN} > build/docs/CNAME"
sshagent(credentials: ['status-im-auto-ssh']) {
sh 'node ci/deploy.js'
}
} }
}
}
post {
always { cleanWs() }
}
}
def buildExample(example=STAGE_NAME) {
def dest = "${WORKSPACE}/build/docs/${example}"
dir("${example}") {
sh 'yarn install --network-concurrency 1 --no-lockfile'
sh 'yarn run build'
sh "mkdir -p ${dest}"
sh "cp -r build/. ${dest}"
}
}
def copyExample(example=STAGE_NAME) {
sh "mkdir -p build/docs/${example}"
sh "cp ${example}/index.html build/docs/${example}/"
}

11
ci/README.md Normal file
View File

@ -0,0 +1,11 @@
# Description
Configuration of CI builds executed under a Jenkins instance at https://ci.status.im/.
# Website
The `Jenkinsfile.gh-pages` file builds the documentation site with this job:
https://ci.infra.status.im/job/website/job/examples.waku.org/
And deploys it via `gh-pages` branch and [GitHub Pages](https://pages.github.com/) to:
https://examples.waku.org/

39
ci/deploy.js Executable file
View File

@ -0,0 +1,39 @@
const { promisify } = require('util')
const { publish } = require('gh-pages')
const ghpublish = promisify(publish)
/* fix for "Unhandled promise rejections" */
process.on('unhandledRejection', err => { throw err })
const Args = process.argv.slice(2)
const USE_HTTPS = Args[0] && Args[0].toUpperCase() === 'HTTPS'
const branch = 'gh-pages'
const org = 'waku-org'
const repo = 'js-waku-examples'
/* use SSH auth by default */
let repoUrl = USE_HTTPS
? `https://github.com/${org}/${repo}.git`
: `git@github.com:${org}/${repo}.git`
/* alternative auth using GitHub user and API token */
if (process.env.GH_USER != undefined) {
repoUrl = (
'https://' + process.env.GH_USER +
':' + process.env.GH_TOKEN +
'@' + `github.com/${org}/${repo}.git`
)
}
const main = async (url, branch)=> {
console.log(`Pushing to: ${url}`)
console.log(`On branch: ${branch}`)
await ghpublish('build/docs', {
repo: url,
branch: branch,
dotfiles: true,
silent: false
})
}
main(repoUrl, branch)

View File

@ -59,6 +59,6 @@
"npm-run-all": "^4.1.5",
"prettier": "^2.5.1",
"react-scripts": "5.0.1",
"typescript": "^4.5.5"
"typescript": "^4.8.2"
}
}

View File

@ -21,7 +21,7 @@ specifiers:
react: ^18.2.0
react-dom: ^18.2.0
react-scripts: 5.0.1
typescript: ^4.5.5
typescript: ^4.8.2
uint8arrays: ^3.1.0
dependencies:
@ -47,8 +47,8 @@ devDependencies:
eslint: 8.21.0
npm-run-all: 4.1.5
prettier: 2.7.1
react-scripts: 5.0.1_hh7noc25gsrzvp6vxmzwopgyr4
typescript: 4.7.4
react-scripts: 5.0.1_e23e7evf6537qu7ubpbcii2cdu
typescript: 4.8.2
packages:
@ -3923,7 +3923,7 @@ packages:
'@types/yargs-parser': 21.0.0
dev: true
/@typescript-eslint/eslint-plugin/5.32.0_iosr3hrei2tubxveewluhu5lhy:
/@typescript-eslint/eslint-plugin/5.32.0_kdwbl65lia4yzlecy2enednvse:
resolution: {integrity: sha512-CHLuz5Uz7bHP2WgVlvoZGhf0BvFakBJKAD/43Ty0emn4wXWv5k01ND0C0fHcl/Im8Td2y/7h44E9pca9qAu2ew==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@ -3934,36 +3934,36 @@ packages:
typescript:
optional: true
dependencies:
'@typescript-eslint/parser': 5.32.0_qugx7qdu5zevzvxaiqyxfiwquq
'@typescript-eslint/parser': 5.32.0_ou2kolaoagz2etaj4kmzu6fily
'@typescript-eslint/scope-manager': 5.32.0
'@typescript-eslint/type-utils': 5.32.0_qugx7qdu5zevzvxaiqyxfiwquq
'@typescript-eslint/utils': 5.32.0_qugx7qdu5zevzvxaiqyxfiwquq
'@typescript-eslint/type-utils': 5.32.0_ou2kolaoagz2etaj4kmzu6fily
'@typescript-eslint/utils': 5.32.0_ou2kolaoagz2etaj4kmzu6fily
debug: 4.3.4
eslint: 8.21.0
functional-red-black-tree: 1.0.1
ignore: 5.2.0
regexpp: 3.2.0
semver: 7.3.7
tsutils: 3.21.0_typescript@4.7.4
typescript: 4.7.4
tsutils: 3.21.0_typescript@4.8.2
typescript: 4.8.2
transitivePeerDependencies:
- supports-color
dev: true
/@typescript-eslint/experimental-utils/5.32.0_qugx7qdu5zevzvxaiqyxfiwquq:
/@typescript-eslint/experimental-utils/5.32.0_ou2kolaoagz2etaj4kmzu6fily:
resolution: {integrity: sha512-/x72MkqLAoOQSOHFxdm17irJ1PNDWtdrMmfacaYniGT26nibak8vxEf9xmoVE+yTYL8N77I2icPtw89Yx6HvNg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
dependencies:
'@typescript-eslint/utils': 5.32.0_qugx7qdu5zevzvxaiqyxfiwquq
'@typescript-eslint/utils': 5.32.0_ou2kolaoagz2etaj4kmzu6fily
eslint: 8.21.0
transitivePeerDependencies:
- supports-color
- typescript
dev: true
/@typescript-eslint/parser/5.32.0_qugx7qdu5zevzvxaiqyxfiwquq:
/@typescript-eslint/parser/5.32.0_ou2kolaoagz2etaj4kmzu6fily:
resolution: {integrity: sha512-IxRtsehdGV9GFQ35IGm5oKKR2OGcazUoiNBxhRV160iF9FoyuXxjY+rIqs1gfnd+4eL98OjeGnMpE7RF/NBb3A==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@ -3975,10 +3975,10 @@ packages:
dependencies:
'@typescript-eslint/scope-manager': 5.32.0
'@typescript-eslint/types': 5.32.0
'@typescript-eslint/typescript-estree': 5.32.0_typescript@4.7.4
'@typescript-eslint/typescript-estree': 5.32.0_typescript@4.8.2
debug: 4.3.4
eslint: 8.21.0
typescript: 4.7.4
typescript: 4.8.2
transitivePeerDependencies:
- supports-color
dev: true
@ -3991,7 +3991,7 @@ packages:
'@typescript-eslint/visitor-keys': 5.32.0
dev: true
/@typescript-eslint/type-utils/5.32.0_qugx7qdu5zevzvxaiqyxfiwquq:
/@typescript-eslint/type-utils/5.32.0_ou2kolaoagz2etaj4kmzu6fily:
resolution: {integrity: sha512-0gSsIhFDduBz3QcHJIp3qRCvVYbqzHg8D6bHFsDMrm0rURYDj+skBK2zmYebdCp+4nrd9VWd13egvhYFJj/wZg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@ -4001,11 +4001,11 @@ packages:
typescript:
optional: true
dependencies:
'@typescript-eslint/utils': 5.32.0_qugx7qdu5zevzvxaiqyxfiwquq
'@typescript-eslint/utils': 5.32.0_ou2kolaoagz2etaj4kmzu6fily
debug: 4.3.4
eslint: 8.21.0
tsutils: 3.21.0_typescript@4.7.4
typescript: 4.7.4
tsutils: 3.21.0_typescript@4.8.2
typescript: 4.8.2
transitivePeerDependencies:
- supports-color
dev: true
@ -4015,7 +4015,7 @@ packages:
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true
/@typescript-eslint/typescript-estree/5.32.0_typescript@4.7.4:
/@typescript-eslint/typescript-estree/5.32.0_typescript@4.8.2:
resolution: {integrity: sha512-ZVAUkvPk3ITGtCLU5J4atCw9RTxK+SRc6hXqLtllC2sGSeMFWN+YwbiJR9CFrSFJ3w4SJfcWtDwNb/DmUIHdhg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@ -4030,13 +4030,13 @@ packages:
globby: 11.1.0
is-glob: 4.0.3
semver: 7.3.7
tsutils: 3.21.0_typescript@4.7.4
typescript: 4.7.4
tsutils: 3.21.0_typescript@4.8.2
typescript: 4.8.2
transitivePeerDependencies:
- supports-color
dev: true
/@typescript-eslint/utils/5.32.0_qugx7qdu5zevzvxaiqyxfiwquq:
/@typescript-eslint/utils/5.32.0_ou2kolaoagz2etaj4kmzu6fily:
resolution: {integrity: sha512-W7lYIAI5Zlc5K082dGR27Fczjb3Q57ECcXefKU/f0ajM5ToM0P+N9NmJWip8GmGu/g6QISNT+K6KYB+iSHjXCQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@ -4045,7 +4045,7 @@ packages:
'@types/json-schema': 7.0.11
'@typescript-eslint/scope-manager': 5.32.0
'@typescript-eslint/types': 5.32.0
'@typescript-eslint/typescript-estree': 5.32.0_typescript@4.7.4
'@typescript-eslint/typescript-estree': 5.32.0_typescript@4.8.2
eslint: 8.21.0
eslint-scope: 5.1.1
eslint-utils: 3.0.0_eslint@8.21.0
@ -6042,7 +6042,7 @@ packages:
source-map: 0.6.1
dev: true
/eslint-config-react-app/7.0.1_x3alemznk2vpfvvnowlkwitfze:
/eslint-config-react-app/7.0.1_4xxghbdbtpkpzboxb63ap6m5cq:
resolution: {integrity: sha512-K6rNzvkIeHaTd8m/QEh1Zko0KI7BACWkkneSs6s9cKZC/J27X3eZR6Upt1jkmZ/4FK+XUOPPxMEN7+lbUXfSlA==}
engines: {node: '>=14.0.0'}
peerDependencies:
@ -6055,19 +6055,19 @@ packages:
'@babel/core': 7.18.10
'@babel/eslint-parser': 7.18.9_xqt7ek4fk233nrovqiamjvck4u
'@rushstack/eslint-patch': 1.1.4
'@typescript-eslint/eslint-plugin': 5.32.0_iosr3hrei2tubxveewluhu5lhy
'@typescript-eslint/parser': 5.32.0_qugx7qdu5zevzvxaiqyxfiwquq
'@typescript-eslint/eslint-plugin': 5.32.0_kdwbl65lia4yzlecy2enednvse
'@typescript-eslint/parser': 5.32.0_ou2kolaoagz2etaj4kmzu6fily
babel-preset-react-app: 10.0.1
confusing-browser-globals: 1.0.11
eslint: 8.21.0
eslint-plugin-flowtype: 8.0.3_bfhyaeqlroxospgntnspvajiaq
eslint-plugin-import: 2.26.0_wuikv5nqgdfyng42xxm7lklfmi
eslint-plugin-jest: 25.7.0_rgnm43ao3zb6h53qs7rzyfjfmm
eslint-plugin-jest: 25.7.0_es3s5ega56ydzpv3u2fqyh4w34
eslint-plugin-jsx-a11y: 6.6.1_eslint@8.21.0
eslint-plugin-react: 7.30.1_eslint@8.21.0
eslint-plugin-react-hooks: 4.6.0_eslint@8.21.0
eslint-plugin-testing-library: 5.6.0_qugx7qdu5zevzvxaiqyxfiwquq
typescript: 4.7.4
eslint-plugin-testing-library: 5.6.0_ou2kolaoagz2etaj4kmzu6fily
typescript: 4.8.2
transitivePeerDependencies:
- '@babel/plugin-syntax-flow'
- '@babel/plugin-transform-react-jsx'
@ -6104,7 +6104,7 @@ packages:
eslint-import-resolver-webpack:
optional: true
dependencies:
'@typescript-eslint/parser': 5.32.0_qugx7qdu5zevzvxaiqyxfiwquq
'@typescript-eslint/parser': 5.32.0_ou2kolaoagz2etaj4kmzu6fily
debug: 3.2.7
eslint-import-resolver-node: 0.3.6
find-up: 2.1.0
@ -6137,7 +6137,7 @@ packages:
'@typescript-eslint/parser':
optional: true
dependencies:
'@typescript-eslint/parser': 5.32.0_qugx7qdu5zevzvxaiqyxfiwquq
'@typescript-eslint/parser': 5.32.0_ou2kolaoagz2etaj4kmzu6fily
array-includes: 3.1.5
array.prototype.flat: 1.3.0
debug: 2.6.9
@ -6158,7 +6158,7 @@ packages:
- supports-color
dev: true
/eslint-plugin-jest/25.7.0_rgnm43ao3zb6h53qs7rzyfjfmm:
/eslint-plugin-jest/25.7.0_es3s5ega56ydzpv3u2fqyh4w34:
resolution: {integrity: sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ==}
engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
peerDependencies:
@ -6171,8 +6171,8 @@ packages:
jest:
optional: true
dependencies:
'@typescript-eslint/eslint-plugin': 5.32.0_iosr3hrei2tubxveewluhu5lhy
'@typescript-eslint/experimental-utils': 5.32.0_qugx7qdu5zevzvxaiqyxfiwquq
'@typescript-eslint/eslint-plugin': 5.32.0_kdwbl65lia4yzlecy2enednvse
'@typescript-eslint/experimental-utils': 5.32.0_ou2kolaoagz2etaj4kmzu6fily
eslint: 8.21.0
jest: 27.5.1
transitivePeerDependencies:
@ -6234,13 +6234,13 @@ packages:
string.prototype.matchall: 4.0.7
dev: true
/eslint-plugin-testing-library/5.6.0_qugx7qdu5zevzvxaiqyxfiwquq:
/eslint-plugin-testing-library/5.6.0_ou2kolaoagz2etaj4kmzu6fily:
resolution: {integrity: sha512-y63TRzPhGCMNsnUwMGJU1MFWc/3GvYw+nzobp9QiyNTTKsgAt5RKAOT1I34+XqVBpX1lC8bScoOjCkP7iRv0Mw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0, npm: '>=6'}
peerDependencies:
eslint: ^7.5.0 || ^8.0.0
dependencies:
'@typescript-eslint/utils': 5.32.0_qugx7qdu5zevzvxaiqyxfiwquq
'@typescript-eslint/utils': 5.32.0_ou2kolaoagz2etaj4kmzu6fily
eslint: 8.21.0
transitivePeerDependencies:
- supports-color
@ -6684,7 +6684,7 @@ packages:
deprecated: Package relocated. Please install and migrate to @fontsource/roboto.
dev: false
/fork-ts-checker-webpack-plugin/6.5.2_o76vzsp5j2es3tw47tgtdagf3m:
/fork-ts-checker-webpack-plugin/6.5.2_6powqha3uet7brcqpdvamgrsxu:
resolution: {integrity: sha512-m5cUmF30xkZ7h4tWUgTAcEaKmUW7tfyUyTqNNOz7OxWJ0v1VWKTcOvH8FWHUwSjlW/356Ijc9vi3XfcPstpQKA==}
engines: {node: '>=10', yarn: '>=1.0.0'}
peerDependencies:
@ -6712,7 +6712,7 @@ packages:
schema-utils: 2.7.0
semver: 7.3.7
tapable: 1.1.3
typescript: 4.7.4
typescript: 4.8.2
webpack: 5.74.0
dev: true
@ -10489,7 +10489,7 @@ packages:
whatwg-fetch: 3.6.2
dev: true
/react-dev-utils/12.0.1_o76vzsp5j2es3tw47tgtdagf3m:
/react-dev-utils/12.0.1_6powqha3uet7brcqpdvamgrsxu:
resolution: {integrity: sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==}
engines: {node: '>=14'}
peerDependencies:
@ -10508,7 +10508,7 @@ packages:
escape-string-regexp: 4.0.0
filesize: 8.0.7
find-up: 5.0.0
fork-ts-checker-webpack-plugin: 6.5.2_o76vzsp5j2es3tw47tgtdagf3m
fork-ts-checker-webpack-plugin: 6.5.2_6powqha3uet7brcqpdvamgrsxu
global-modules: 2.0.0
globby: 11.1.0
gzip-size: 6.0.0
@ -10523,7 +10523,7 @@ packages:
shell-quote: 1.7.3
strip-ansi: 6.0.1
text-table: 0.2.0
typescript: 4.7.4
typescript: 4.8.2
webpack: 5.74.0
transitivePeerDependencies:
- eslint
@ -10560,7 +10560,7 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/react-scripts/5.0.1_hh7noc25gsrzvp6vxmzwopgyr4:
/react-scripts/5.0.1_e23e7evf6537qu7ubpbcii2cdu:
resolution: {integrity: sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ==}
engines: {node: '>=14.0.0'}
hasBin: true
@ -10588,7 +10588,7 @@ packages:
dotenv: 10.0.0
dotenv-expand: 5.1.0
eslint: 8.21.0
eslint-config-react-app: 7.0.1_x3alemznk2vpfvvnowlkwitfze
eslint-config-react-app: 7.0.1_4xxghbdbtpkpzboxb63ap6m5cq
eslint-webpack-plugin: 3.2.0_u2suxbtqimpjcabkd5w2ufy4qm
file-loader: 6.2.0_webpack@5.74.0
fs-extra: 10.1.0
@ -10606,7 +10606,7 @@ packages:
prompts: 2.4.2
react: 18.2.0
react-app-polyfill: 3.0.0
react-dev-utils: 12.0.1_o76vzsp5j2es3tw47tgtdagf3m
react-dev-utils: 12.0.1_6powqha3uet7brcqpdvamgrsxu
react-refresh: 0.11.0
resolve: 1.22.1
resolve-url-loader: 4.0.0
@ -10616,7 +10616,7 @@ packages:
style-loader: 3.3.1_webpack@5.74.0
tailwindcss: 3.1.8_postcss@8.4.16
terser-webpack-plugin: 5.3.3_webpack@5.74.0
typescript: 4.7.4
typescript: 4.8.2
webpack: 5.74.0
webpack-dev-server: 4.9.3_webpack@5.74.0
webpack-manifest-plugin: 4.1.1_webpack@5.74.0
@ -11784,14 +11784,14 @@ packages:
resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==}
dev: true
/tsutils/3.21.0_typescript@4.7.4:
/tsutils/3.21.0_typescript@4.8.2:
resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
engines: {node: '>= 6'}
peerDependencies:
typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta'
dependencies:
tslib: 1.14.1
typescript: 4.7.4
typescript: 4.8.2
dev: true
/type-check/0.3.2:
@ -11842,8 +11842,8 @@ packages:
is-typedarray: 1.0.0
dev: true
/typescript/4.7.4:
resolution: {integrity: sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==}
/typescript/4.8.2:
resolution: {integrity: sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw==}
engines: {node: '>=4.2.0'}
hasBin: true
dev: true

View File

@ -13,7 +13,7 @@ export async function saveKeyPairToStorage(
const data = {
salt: utils.bytesToHex(salt),
iv: utils.bytesToHex(iv),
cipher: utils.bytesToHex(cipher),
cipher: utils.bytesToHex(new Uint8Array(cipher)),
};
localStorage.setItem("cipherEncryptionKeyPair", JSON.stringify(data));

5
package.json Normal file
View File

@ -0,0 +1,5 @@
{
"dependencies": {
"gh-pages": "^4.0.0"
}
}

View File

@ -17,7 +17,7 @@
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/relay-angular-chat",
"outputPath": "build",
"index": "src/index.html",
"main": "src/main.ts",
"tsConfig": "tsconfig.app.json",