This commit is contained in:
Eugene Pankov
2021-10-24 21:50:55 +02:00
parent c61c816e32
commit eae970f969
50 changed files with 1521 additions and 1385 deletions

12
.bumpversion.cfg Normal file
View File

@@ -0,0 +1,12 @@
[bumpversion]
current_version = 1.0.0
commit = True
tag = True
[bumpversion:file:frontend/package.json]
search = "version": "{current_version}"
replace = "version": "{new_version}"
[bumpversion:file:backend/pyproject.toml]
search = version = "{current_version}"
replace = version = "{new_version}"

View File

@@ -11,3 +11,6 @@ insert_final_newline = true
[*.md] [*.md]
trim_trailing_whitespace = false trim_trailing_whitespace = false
[*.ts]
indent_size = 2

36
.github/workflows/lint.yml vendored Normal file
View File

@@ -0,0 +1,36 @@
name: Lint
on: [push, pull_request]
jobs:
Lint:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2.3.4
with:
fetch-depth: 0
- name: Installing Node
uses: actions/setup-node@v2.4.0
with:
node-version: 14
- name: Install frontend deps
working-directory: frontend
run: |
npm i -g yarn@1.19.1
yarn
- name: Lint frontend
working-directory: frontend
run: yarn lint
- name: Install backend deps
working-directory: backend
run: |
pip3 install poetry
poetry install
- name: Lint backend
working-directory: frontend
run: flake8 .

7
backend/.flake8 Normal file
View File

@@ -0,0 +1,7 @@
[flake8]
ignore=E501,D103,C901,D203,W504,S607,S603,S404,S606,S322,S410,S320,B010
exclude = .git,__pycache__,help,static,misc,locale,templates,tests,deployment,migrations,elements/ai/scripts
max-complexity = 40
builtins = _
per-file-ignores = scripts/*:T001,E402
select = C,E,F,W,B,B902

View File

@@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "tabby-web" name = "tabby-web"
version = "0.1.0" version = "1.0.0"
description = "" description = ""
authors = ["Your Name <you@example.com>"] authors = ["Your Name <you@example.com>"]

View File

@@ -1,214 +0,0 @@
import fsspec
import os
import asyncio
import random
from django.conf import settings
from django.contrib.auth import logout
from dataclasses import dataclass
from pathlib import Path
from rest_framework import fields, status
from rest_framework.exceptions import APIException, PermissionDenied, NotFound
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.mixins import ListModelMixin, RetrieveModelMixin, UpdateModelMixin
from rest_framework.views import APIView
from rest_framework.viewsets import GenericViewSet, ModelViewSet
from rest_framework.serializers import ModelSerializer, Serializer
from rest_framework_dataclasses.serializers import DataclassSerializer
from social_django.models import UserSocialAuth
from typing import List
from urllib.parse import urlparse
from .gateway import GatewayAdminConnection
from .sponsors import check_is_sponsor, check_is_sponsor_cached
from .models import Config, Gateway, User
@dataclass
class AppVersion:
version: str
plugins: List[str]
class AppVersionSerializer(DataclassSerializer):
class Meta:
dataclass = AppVersion
class GatewaySerializer(ModelSerializer):
url = fields.SerializerMethodField()
auth_token = fields.CharField()
class Meta:
fields = '__all__'
model = Gateway
def get_url(self, gw):
return f'{"wss" if gw.secure else "ws"}://{gw.host}:{gw.port}/'
class ConfigSerializer(ModelSerializer):
name = fields.CharField(required=False)
class Meta:
model = Config
read_only_fields = ('user', 'created_at', 'modified_at')
fields = '__all__'
class ConfigViewSet(ModelViewSet):
queryset = Config.objects.all()
serializer_class = ConfigSerializer
permission_classes = [IsAuthenticated]
def get_queryset(self):
if self.request.user.is_authenticated:
return Config.objects.filter(user=self.request.user)
return Config.objects.none()
def perform_create(self, serializer):
serializer.save(user=self.request.user)
class AppVersionViewSet(ListModelMixin, GenericViewSet):
serializer_class = AppVersionSerializer
lookup_field = 'id'
lookup_value_regex = r'[\w\d.-]+'
queryset = ''
def _get_versions(self):
fs = fsspec.filesystem(urlparse(settings.APP_DIST_STORAGE).scheme)
return [
self._get_version(x['name'])
for x in fs.listdir(settings.APP_DIST_STORAGE)
if x['type'] == 'directory'
]
def _get_version(self, dir):
fs = fsspec.filesystem(urlparse(settings.APP_DIST_STORAGE).scheme)
plugins = [
os.path.basename(x['name'])
for x in fs.listdir(dir)
if x['type'] == 'directory' and os.path.basename(x['name'])
not in [
'tabby-web-container',
'tabby-web-demo',
]
]
return AppVersion(
version=os.path.basename(dir),
plugins=plugins,
)
def list(self, request, *args, **kwargs):
return Response(
self.serializer_class(
self._get_versions(),
many=True,
).data
)
class UserSerializer(ModelSerializer):
id = fields.IntegerField()
is_pro = fields.SerializerMethodField()
is_sponsor = fields.SerializerMethodField()
github_username = fields.SerializerMethodField()
class Meta:
model = User
fields = (
'id',
'username',
'active_config',
'custom_connection_gateway',
'custom_connection_gateway_token',
'config_sync_token',
'is_pro',
'is_sponsor',
'github_username',
)
read_only_fields = ('id', 'username')
def get_is_pro(self, obj):
return obj.force_pro or not settings.GITHUB_ELIGIBLE_SPONSORSHIPS or check_is_sponsor_cached(obj)
def get_is_sponsor(self, obj):
return check_is_sponsor_cached(obj)
def get_github_username(self, obj):
social_auth = UserSocialAuth.objects.filter(user=obj, provider='github').first()
if not social_auth:
return None
return social_auth.extra_data.get('login')
class UserViewSet(RetrieveModelMixin, UpdateModelMixin, GenericViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
def get_object(self):
if self.request.user.is_authenticated:
return self.request.user
raise PermissionDenied()
class LogoutView(APIView):
def post(self, request, format=None):
logout(request)
return Response(None)
class InstanceInfoSerializer(Serializer):
login_enabled = fields.BooleanField()
homepage_enabled = fields.BooleanField()
class InstanceInfoViewSet(RetrieveModelMixin, GenericViewSet):
queryset = '' # type: ignore
serializer_class = InstanceInfoSerializer
def get_object(self):
return {
'login_enabled': settings.ENABLE_LOGIN,
'homepage_enabled': settings.ENABLE_HOMEPAGE,
}
class NoGatewaysError(APIException):
status_code = status.HTTP_503_SERVICE_UNAVAILABLE
default_detail = 'No connection gateways available.'
default_code = 'no_gateways'
class ChooseGatewayViewSet(RetrieveModelMixin, GenericViewSet):
queryset = Gateway.objects.filter(enabled=True)
serializer_class = GatewaySerializer
async def _authorize_client(self, gw):
c = GatewayAdminConnection(gw)
await c.connect()
token = await c.authorize_client()
await c.close()
return token
def get_object(self):
gateways = list(self.queryset)
random.shuffle(gateways)
if not len(gateways):
raise NotFound()
loop = asyncio.new_event_loop()
try:
for gw in gateways:
try:
gw.auth_token = loop.run_until_complete(self._authorize_client(gw))
except ConnectionError:
continue
return gw
raise NoGatewaysError()
finally:
loop.close()

View File

@@ -0,0 +1,18 @@
from django.urls import path, include
from rest_framework import routers
from . import app_version, auth, config, gateway, info, user
router = routers.DefaultRouter(trailing_slash=False)
router.register('api/1/configs', config.ConfigViewSet)
router.register('api/1/versions', app_version.AppVersionViewSet, basename='app-versions')
urlpatterns = [
path('api/1/auth/logout', auth.LogoutView.as_view()),
path('api/1/user', user.UserViewSet.as_view({'get': 'retrieve', 'put': 'update'})),
path('api/1/instance-info', info.InstanceInfoViewSet.as_view({'get': 'retrieve'})),
path('api/1/gateways/choose', gateway.ChooseGatewayViewSet.as_view({'post': 'retrieve'})),
path('', include(router.urls)),
]

View File

@@ -0,0 +1,64 @@
import fsspec
import os
from django.conf import settings
from django.utils.decorators import method_decorator
from django.views.decorators.cache import cache_page
from dataclasses import dataclass
from rest_framework.response import Response
from rest_framework.mixins import ListModelMixin
from rest_framework.viewsets import GenericViewSet
from rest_framework_dataclasses.serializers import DataclassSerializer
from typing import List
from urllib.parse import urlparse
@dataclass
class AppVersion:
version: str
plugins: List[str]
class AppVersionSerializer(DataclassSerializer):
class Meta:
dataclass = AppVersion
class AppVersionViewSet(ListModelMixin, GenericViewSet):
serializer_class = AppVersionSerializer
lookup_field = 'id'
lookup_value_regex = r'[\w\d.-]+'
queryset = ''
def _get_versions(self):
fs = fsspec.filesystem(urlparse(settings.APP_DIST_STORAGE).scheme)
return [
self._get_version(x['name'])
for x in fs.listdir(settings.APP_DIST_STORAGE)
if x['type'] == 'directory'
]
def _get_version(self, dir):
fs = fsspec.filesystem(urlparse(settings.APP_DIST_STORAGE).scheme)
plugins = [
os.path.basename(x['name'])
for x in fs.listdir(dir)
if x['type'] == 'directory' and os.path.basename(x['name'])
not in [
'tabby-web-container',
'tabby-web-demo',
]
]
return AppVersion(
version=os.path.basename(dir),
plugins=plugins,
)
@method_decorator(cache_page(60))
def list(self, request, *args, **kwargs):
return Response(
self.serializer_class(
self._get_versions(),
many=True,
).data
)

View File

@@ -0,0 +1,9 @@
from django.contrib.auth import logout
from rest_framework.response import Response
from rest_framework.views import APIView
class LogoutView(APIView):
def post(self, request, format=None):
logout(request)
return Response(None)

View File

@@ -0,0 +1,28 @@
from rest_framework import fields
from rest_framework.permissions import IsAuthenticated
from rest_framework.viewsets import ModelViewSet
from rest_framework.serializers import ModelSerializer
from ..models import Config
class ConfigSerializer(ModelSerializer):
name = fields.CharField(required=False)
class Meta:
model = Config
read_only_fields = ('user', 'created_at', 'modified_at')
fields = '__all__'
class ConfigViewSet(ModelViewSet):
queryset = Config.objects.all()
serializer_class = ConfigSerializer
permission_classes = [IsAuthenticated]
def get_queryset(self):
if self.request.user.is_authenticated:
return Config.objects.filter(user=self.request.user)
return Config.objects.none()
def perform_create(self, serializer):
serializer.save(user=self.request.user)

View File

@@ -0,0 +1,58 @@
import asyncio
import random
from rest_framework import fields, status
from rest_framework.exceptions import APIException, NotFound
from rest_framework.mixins import RetrieveModelMixin
from rest_framework.viewsets import GenericViewSet
from rest_framework.serializers import ModelSerializer
from ..gateway import GatewayAdminConnection
from ..models import Gateway
class GatewaySerializer(ModelSerializer):
url = fields.SerializerMethodField()
auth_token = fields.CharField()
class Meta:
fields = '__all__'
model = Gateway
def get_url(self, gw):
return f'{"wss" if gw.secure else "ws"}://{gw.host}:{gw.port}/'
class NoGatewaysError(APIException):
status_code = status.HTTP_503_SERVICE_UNAVAILABLE
default_detail = 'No connection gateways available.'
default_code = 'no_gateways'
class ChooseGatewayViewSet(RetrieveModelMixin, GenericViewSet):
queryset = Gateway.objects.filter(enabled=True)
serializer_class = GatewaySerializer
async def _authorize_client(self, gw):
c = GatewayAdminConnection(gw)
await c.connect()
token = await c.authorize_client()
await c.close()
return token
def get_object(self):
gateways = list(self.queryset)
random.shuffle(gateways)
if not len(gateways):
raise NotFound()
loop = asyncio.new_event_loop()
try:
for gw in gateways:
try:
gw.auth_token = loop.run_until_complete(self._authorize_client(gw))
except ConnectionError:
continue
return gw
raise NoGatewaysError()
finally:
loop.close()

View File

@@ -0,0 +1,21 @@
from django.conf import settings
from rest_framework import fields
from rest_framework.mixins import RetrieveModelMixin
from rest_framework.viewsets import GenericViewSet
from rest_framework.serializers import Serializer
class InstanceInfoSerializer(Serializer):
login_enabled = fields.BooleanField()
homepage_enabled = fields.BooleanField()
class InstanceInfoViewSet(RetrieveModelMixin, GenericViewSet):
queryset = '' # type: ignore
serializer_class = InstanceInfoSerializer
def get_object(self):
return {
'login_enabled': settings.ENABLE_LOGIN,
'homepage_enabled': settings.ENABLE_HOMEPAGE,
}

View File

@@ -0,0 +1,55 @@
from django.conf import settings
from rest_framework import fields
from rest_framework.exceptions import PermissionDenied
from rest_framework.mixins import RetrieveModelMixin, UpdateModelMixin
from rest_framework.viewsets import GenericViewSet
from rest_framework.serializers import ModelSerializer
from social_django.models import UserSocialAuth
from ..sponsors import check_is_sponsor_cached
from ..models import User
class UserSerializer(ModelSerializer):
id = fields.IntegerField()
is_pro = fields.SerializerMethodField()
is_sponsor = fields.SerializerMethodField()
github_username = fields.SerializerMethodField()
class Meta:
model = User
fields = (
'id',
'username',
'active_config',
'custom_connection_gateway',
'custom_connection_gateway_token',
'config_sync_token',
'is_pro',
'is_sponsor',
'github_username',
)
read_only_fields = ('id', 'username')
def get_is_pro(self, obj):
return obj.force_pro or not settings.GITHUB_ELIGIBLE_SPONSORSHIPS or check_is_sponsor_cached(obj)
def get_is_sponsor(self, obj):
return check_is_sponsor_cached(obj)
def get_github_username(self, obj):
social_auth = UserSocialAuth.objects.filter(user=obj, provider='github').first()
if not social_auth:
return None
return social_auth.extra_data.get('login')
class UserViewSet(RetrieveModelMixin, UpdateModelMixin, GenericViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
def get_object(self):
if self.request.user.is_authenticated:
return self.request.user
raise PermissionDenied()

View File

@@ -39,7 +39,7 @@ def check_is_sponsor(user: User) -> bool:
query = ''' query = '''
query { query {
user (login: "eugeny") { viewer {
sponsorshipsAsSponsor(%s) { sponsorshipsAsSponsor(%s) {
pageInfo { pageInfo {
startCursor startCursor

View File

@@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

View File

@@ -1,23 +1,17 @@
from django.urls import path, re_path, include from django.urls import path, include
from rest_framework import routers
from . import api from . import api
from . import views from . import views
router = routers.DefaultRouter(trailing_slash=False)
router.register('api/1/configs', api.ConfigViewSet)
router.register('api/1/versions', api.AppVersionViewSet, basename='app-versions')
urlpatterns = [ urlpatterns = [
path('api/1/auth/logout', api.LogoutView.as_view()), *[
path('api/1/user', api.UserViewSet.as_view({'get': 'retrieve', 'put': 'update'})), path(p, views.IndexView.as_view())
path('api/1/instance-info', api.InstanceInfoViewSet.as_view({'get': 'retrieve'})), for p in ['', 'login', 'app', 'about', 'features']
path('api/1/gateways/choose', api.ChooseGatewayViewSet.as_view({'post': 'retrieve'})), ],
re_path('^(|login|app|about|features)$', views.IndexView.as_view()),
path('terminal', views.TerminalView.as_view()),
path('app-dist/<version>/<path:path>', views.AppDistView.as_view()), path('app-dist/<version>/<path:path>', views.AppDistView.as_view()),
path('', include(router.urls)), path('terminal', views.TerminalView.as_view()),
path('', include(api.urlpatterns)),
] ]

View File

@@ -4,8 +4,8 @@ import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'tabby.settings') os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'tabby.settings')
django.setup() django.setup()
from channels.routing import ProtocolTypeRouter from channels.routing import ProtocolTypeRouter # noqa
from django.core.asgi import get_asgi_application from django.core.asgi import get_asgi_application # noqa
application = ProtocolTypeRouter({ application = ProtocolTypeRouter({
'http': get_asgi_application(), 'http': get_asgi_application(),

View File

@@ -1,7 +1,7 @@
import logging import logging
from tabby.app.models import User from tabby.app.models import User
from django.conf import settings from django.conf import settings
from django.contrib.auth import hashers, logout, login from django.contrib.auth import login
from pyga.requests import Tracker, Page, Session, Visitor from pyga.requests import Tracker, Page, Session, Visitor

View File

@@ -2,7 +2,6 @@ parser: '@typescript-eslint/parser'
parserOptions: parserOptions:
project: project:
- tsconfig.json - tsconfig.json
- '*/tsconfig.typings.json'
extends: extends:
- 'plugin:@typescript-eslint/all' - 'plugin:@typescript-eslint/all'
plugins: plugins:
@@ -18,7 +17,7 @@ rules:
- never - never
'@typescript-eslint/indent': '@typescript-eslint/indent':
- error - error
- 4 - 2
'@typescript-eslint/explicit-member-accessibility': '@typescript-eslint/explicit-member-accessibility':
- error - error
- accessibility: no-public - accessibility: no-public
@@ -121,3 +120,10 @@ rules:
'@typescript-eslint/no-unsafe-argument': off '@typescript-eslint/no-unsafe-argument': off
'@typescript-eslint/restrict-plus-operands': off '@typescript-eslint/restrict-plus-operands': off
'@typescript-eslint/space-infix-ops': off '@typescript-eslint/space-infix-ops': off
'@typescript-eslint/explicit-module-boundary-types': off
overrides:
- files: '*.service.ts'
rules:
'@typescript-eslint/explicit-module-boundary-types':
- error

View File

@@ -3,6 +3,7 @@
"version": "1.0.0", "version": "1.0.0",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"lint": "eslint src",
"build": "webpack --progress", "build": "webpack --progress",
"watch": "DEV=1 webpack --progress --watch", "watch": "DEV=1 webpack --progress --watch",
"build:server": "webpack --progress -c webpack.config.server.js", "build:server": "webpack --progress -c webpack.config.server.js",
@@ -33,8 +34,8 @@
"@nguniversal/express-engine": "^11.1.0", "@nguniversal/express-engine": "^11.1.0",
"@tabby-gang/to-string-loader": "^1.1.7-beta.1", "@tabby-gang/to-string-loader": "^1.1.7-beta.1",
"@types/node": "^11.9.5", "@types/node": "^11.9.5",
"@typescript-eslint/eslint-plugin": "^4.28.4", "@typescript-eslint/eslint-plugin": "^5.1.0",
"@typescript-eslint/parser": "^4.28.4", "@typescript-eslint/parser": "^5.1.0",
"apply-loader": "^2.0.0", "apply-loader": "^2.0.0",
"bootstrap": "^5.0.1", "bootstrap": "^5.0.1",
"buffer": "^6.0.3", "buffer": "^6.0.3",
@@ -66,6 +67,7 @@
"source-map-support": "^0.5.19", "source-map-support": "^0.5.19",
"source-sans-pro": "^2.45.0", "source-sans-pro": "^2.45.0",
"style-loader": "^0.23.1", "style-loader": "^0.23.1",
"three": "^0.119.0",
"throng": "^5.0.0", "throng": "^5.0.0",
"typescript": "~4.1", "typescript": "~4.1",
"val-loader": "^4.0.0", "val-loader": "^4.0.0",
@@ -73,7 +75,6 @@
"webpack": "^5.38.1", "webpack": "^5.38.1",
"webpack-bundle-analyzer": "^4.4.2", "webpack-bundle-analyzer": "^4.4.2",
"webpack-cli": "^4.7.2", "webpack-cli": "^4.7.2",
"three": "^0.119.0",
"zone.js": "^0.11.4" "zone.js": "^0.11.4"
} }
} }

View File

@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-extraneous-class */
import { Component } from '@angular/core' import { Component } from '@angular/core'
@Component({ @Component({

View File

@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-extraneous-class */
import { NgModule } from '@angular/core' import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser' import { BrowserModule } from '@angular/platform-browser'
import { BrowserAnimationsModule } from '@angular/platform-browser/animations' import { BrowserAnimationsModule } from '@angular/platform-browser/animations'

View File

@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-extraneous-class */
import { NgModule } from '@angular/core' import { NgModule } from '@angular/core'
import { ServerModule, ServerTransferStateModule } from '@angular/platform-server' import { ServerModule, ServerTransferStateModule } from '@angular/platform-server'
import { AppModule } from './app.module' import { AppModule } from './app.module'

View File

@@ -23,9 +23,6 @@ export class ConfigModalComponent {
) { ) {
} }
async ngOnInit () {
}
cancel () { cancel () {
this.modalInstance.dismiss() this.modalInstance.dismiss()
} }
@@ -47,6 +44,9 @@ export class ConfigModalComponent {
} }
async deleteConfig () { async deleteConfig () {
if (!this.configService.activeConfig) {
return
}
if (confirm('Delete this config? This cannot be undone.')) { if (confirm('Delete this config? This cannot be undone.')) {
await this.configService.deleteConfig(this.configService.activeConfig) await this.configService.deleteConfig(this.configService.activeConfig)
} }

View File

@@ -23,13 +23,13 @@ export class SettingsModalComponent {
private modalInstance: NgbActiveModal, private modalInstance: NgbActiveModal,
private loginService: LoginService, private loginService: LoginService,
) { ) {
if (!loginService.user) {
return
}
this.user = { ...loginService.user } this.user = { ...loginService.user }
this.customGatewayEnabled = !!this.user.custom_connection_gateway this.customGatewayEnabled = !!this.user.custom_connection_gateway
} }
async ngOnInit () {
}
async apply () { async apply () {
Object.assign(this.loginService.user, this.user) Object.assign(this.loginService.user, this.user)
this.modalInstance.close() this.modalInstance.close()

View File

@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-extraneous-class */
import { NgModule } from '@angular/core' import { NgModule } from '@angular/core'
import { NgbDropdownModule, NgbModalModule, NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap' import { NgbDropdownModule, NgbModalModule, NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'
import { CommonModule } from '@angular/common' import { CommonModule } from '@angular/common'

View File

@@ -8,6 +8,11 @@ import { UpgradeModalComponent } from '../components/upgradeModal.component'
import { Config, Gateway, Version } from 'src/api' import { Config, Gateway, Version } from 'src/api'
import { LoginService, CommonService } from 'src/common' import { LoginService, CommonService } from 'src/common'
export interface ServiceMessage {
_: string
[k: string]: any
}
export class SocketProxy { export class SocketProxy {
connect$ = new Subject<void>() connect$ = new Subject<void>()
data$ = new Subject<Uint8Array>() data$ = new Subject<Uint8Array>()
@@ -51,8 +56,12 @@ export class SocketProxy {
} }
this.options = options this.options = options
this.url = this.loginService.user?.custom_connection_gateway if (this.loginService.user?.custom_connection_gateway) {
this.authToken = this.loginService.user?.custom_connection_gateway_token this.url = this.loginService.user.custom_connection_gateway
}
if (this.loginService.user?.custom_connection_gateway_token) {
this.authToken = this.loginService.user.custom_connection_gateway_token
}
if (!this.url) { if (!this.url) {
try { try {
const gateway = await this.appConnector.chooseConnectionGateway() const gateway = await this.appConnector.chooseConnectionGateway()
@@ -69,12 +78,12 @@ export class SocketProxy {
this.close(err) this.close(err)
return return
} }
this.webSocket.onerror = err => { this.webSocket.onerror = () => {
this.close(new Error(`Failed to connect to the connection gateway at ${this.url}`)) this.close(new Error(`Failed to connect to the connection gateway at ${this.url}`))
return return
} }
this.webSocket.onmessage = async event => { this.webSocket.onmessage = async event => {
if (typeof(event.data) === 'string') { if (typeof event.data === 'string') {
this.handleServiceMessage(JSON.parse(event.data)) this.handleServiceMessage(JSON.parse(event.data))
} else { } else {
this.data$.next(Buffer.from(await event.data.arrayBuffer())) this.data$.next(Buffer.from(await event.data.arrayBuffer()))
@@ -85,7 +94,7 @@ export class SocketProxy {
} }
} }
handleServiceMessage (msg) { handleServiceMessage (msg: ServiceMessage): void {
if (msg._ === 'hello') { if (msg._ === 'hello') {
this.sendServiceMessage({ this.sendServiceMessage({
_: 'hello', _: 'hello',
@@ -102,7 +111,7 @@ export class SocketProxy {
this.connect$.next() this.connect$.next()
this.connect$.complete() this.connect$.complete()
for (const b of this.initialBuffers) { for (const b of this.initialBuffers) {
this.webSocket.send(b) this.webSocket?.send(b)
} }
this.initialBuffers = [] this.initialBuffers = []
} else if (msg._ === 'error') { } else if (msg._ === 'error') {
@@ -113,8 +122,8 @@ export class SocketProxy {
} }
} }
sendServiceMessage (msg) { sendServiceMessage (msg: ServiceMessage): void {
this.webSocket.send(JSON.stringify(msg)) this.webSocket?.send(JSON.stringify(msg))
} }
write (chunk: Buffer): void { write (chunk: Buffer): void {
@@ -162,7 +171,7 @@ export class AppConnectorService {
}) })
} }
setState (config: Config, version: Version) { setState (config: Config, version: Version): void {
this.config = config this.config = config
this.version = version this.version = version
} }
@@ -200,7 +209,7 @@ export class AppConnectorService {
] ]
} }
createSocket () { createSocket (): SocketProxy {
return this.zone.run(() => { return this.zone.run(() => {
const socket = new SocketProxy(this.injector) const socket = new SocketProxy(this.injector)
this.sockets.push(socket) this.sockets.push(socket)
@@ -213,7 +222,7 @@ export class AppConnectorService {
async chooseConnectionGateway (): Promise<Gateway> { async chooseConnectionGateway (): Promise<Gateway> {
try { try {
return await this.http.post('/api/1/gateways/choose', {}).toPromise() return this.http.post('/api/1/gateways/choose', {}).toPromise()
} catch (err){ } catch (err){
if (err.status === 503) { if (err.status === 503) {
throw new Error('All connections gateway are unavailable right now') throw new Error('All connections gateway are unavailable right now')

View File

@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-extraneous-class */
import { ModuleWithProviders, NgModule } from '@angular/core' import { ModuleWithProviders, NgModule } from '@angular/core'
import { HttpClientXsrfModule, HTTP_INTERCEPTORS } from '@angular/common/http' import { HttpClientXsrfModule, HTTP_INTERCEPTORS } from '@angular/common/http'
import { BackendXsrfInterceptor, UniversalInterceptor } from './interceptor' import { BackendXsrfInterceptor, UniversalInterceptor } from './interceptor'
@@ -14,7 +15,7 @@ export class CommonAppModule {
providers: [ providers: [
{ provide: HTTP_INTERCEPTORS, useClass: UniversalInterceptor, multi: true }, { provide: HTTP_INTERCEPTORS, useClass: UniversalInterceptor, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: BackendXsrfInterceptor, multi: true }, { provide: HTTP_INTERCEPTORS, useClass: BackendXsrfInterceptor, multi: true },
] ],
} }
} }
} }

View File

@@ -28,11 +28,11 @@ export class BackendXsrfInterceptor implements HttpInterceptor {
intercept (req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { intercept (req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (this.commonService.backendURL && req.url.startsWith(this.commonService.backendURL)) { if (this.commonService.backendURL && req.url.startsWith(this.commonService.backendURL)) {
let token = this.tokenExtractor.getToken() as string; const token = this.tokenExtractor.getToken()
if (token !== null) { if (token !== null) {
req = req.clone({ setHeaders: { 'X-XSRF-TOKEN': token } }); req = req.clone({ setHeaders: { 'X-XSRF-TOKEN': token } })
} }
} }
return next.handle(req); return next.handle(req)
} }
} }

View File

@@ -5,7 +5,7 @@ export class CommonService {
backendURL: string backendURL: string
constructor (@Inject('BACKEND_URL') @Optional() ssrBackendURL: string) { constructor (@Inject('BACKEND_URL') @Optional() ssrBackendURL: string) {
const tag = (document.querySelector('meta[property=x-tabby-web-backend-url]') as HTMLMetaElement) const tag = document.querySelector('meta[property=x-tabby-web-backend-url]')! as HTMLMetaElement
if (ssrBackendURL) { if (ssrBackendURL) {
this.backendURL = ssrBackendURL this.backendURL = ssrBackendURL
tag.content = ssrBackendURL tag.content = ssrBackendURL

View File

@@ -16,8 +16,8 @@ export class ConfigService {
versions: Version[] = [] versions: Version[] = []
ready$ = new AsyncSubject<void>() ready$ = new AsyncSubject<void>()
get activeConfig (): Config { return this._activeConfig } get activeConfig (): Config | null { return this._activeConfig }
get activeVersion (): Version { return this._activeVersion } get activeVersion (): Version | null { return this._activeVersion }
private _activeConfig: Config|null = null private _activeConfig: Config|null = null
private _activeVersion: Version|null = null private _activeVersion: Version|null = null
@@ -29,7 +29,7 @@ export class ConfigService {
this.init() this.init()
} }
async updateUser () { async updateUser (): Promise<void> {
if (!this.loginService.user) { if (!this.loginService.user) {
return return
} }
@@ -57,24 +57,24 @@ export class ConfigService {
return config return config
} }
getLatestStableVersion () { getLatestStableVersion (): Version {
return this.versions[0] return this.versions[0]
} }
async duplicateActiveConfig () { async duplicateActiveConfig (): Promise<void> {
let copy = { ...this._activeConfig, pk: undefined, id: undefined } let copy = { ...this._activeConfig, pk: undefined, id: undefined }
if (this.loginService.user) { if (this.loginService.user) {
copy = await this.http.post('/api/1/configs', copy).toPromise() copy = await this.http.post('/api/1/configs', copy).toPromise()
} }
this.configs.push(copy) this.configs.push(copy as any)
} }
async selectVersion (version: Version) { async selectVersion (version: Version): Promise<void> {
this._activeVersion = version this._activeVersion = version
this.activeVersion$.next(version) this.activeVersion$.next(version)
} }
async selectConfig (config: Config) { async selectConfig (config: Config): Promise<void> {
let matchingVersion = this.versions.find(x => x.version === config.last_used_with_version) let matchingVersion = this.versions.find(x => x.version === config.last_used_with_version)
if (!matchingVersion) { if (!matchingVersion) {
// TODO ask to upgrade // TODO ask to upgrade
@@ -90,13 +90,13 @@ export class ConfigService {
} }
} }
async selectDefaultConfig () { async selectDefaultConfig (): Promise<void> {
await this.ready$.toPromise() await this.ready$.toPromise()
await this.loginService.ready$.toPromise() await this.loginService.ready$.toPromise()
this.selectConfig(this.configs.find(c => c.id === this.loginService.user?.active_config) ?? this.configs[0]) this.selectConfig(this.configs.find(c => c.id === this.loginService.user?.active_config) ?? this.configs[0])
} }
async deleteConfig (config: Config) { async deleteConfig (config: Config): Promise<void> {
if (this.loginService.user) { if (this.loginService.user) {
await this.http.delete(`/api/1/configs/${config.id}`).toPromise() await this.http.delete(`/api/1/configs/${config.id}`).toPromise()
} }

View File

@@ -13,7 +13,7 @@ export class LoginService {
this.init() this.init()
} }
async updateUser () { async updateUser (): Promise<void> {
if (!this.user) { if (!this.user) {
return return
} }

View File

@@ -59,7 +59,7 @@ export class DemoSocketProxy {
error$ = new Subject<Buffer>() error$ = new Subject<Buffer>()
close$ = new Subject<Buffer>() close$ = new Subject<Buffer>()
async connect (options) { async connect () {
this.error$.next(new Error('This web demo can\'t actually access Internet, but feel free to download the release and try it out!')) this.error$.next(new Error('This web demo can\'t actually access Internet, but feel free to download the release and try it out!'))
} }
} }

View File

@@ -23,11 +23,11 @@ export class HomeComponent {
navLinks = [ navLinks = [
{ {
title: 'About Tabby', title: 'About Tabby',
link: '/' link: '/',
}, },
{ {
title: 'Features', title: 'Features',
link: '/features' link: '/features',
}, },
] ]
@@ -55,7 +55,7 @@ export class HomeComponent {
minWidth: 200.00, minWidth: 200.00,
scale: 1.00, scale: 1.00,
scaleMobile: 1.00, scaleMobile: 1.00,
color: 0x70f color: 0x70f,
}) })
} }

View File

@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-extraneous-class */
import { NgModule } from '@angular/core' import { NgModule } from '@angular/core'
import { NgbNavModule } from '@ng-bootstrap/ng-bootstrap' import { NgbNavModule } from '@ng-bootstrap/ng-bootstrap'
import { CommonModule } from '@angular/common' import { CommonModule } from '@angular/common'

View File

@@ -1,9 +1,10 @@
/* eslint-disable */
import { extend, mobileCheck, q, color2Hex } from 'vanta/src/helpers.js' import { extend, mobileCheck, q, color2Hex } from 'vanta/src/helpers.js'
// const DEBUGMODE = window.location.toString().indexOf('VANTADEBUG') !== -1 // const DEBUGMODE = window.location.toString().indexOf('VANTADEBUG') !== -1
const win = typeof window == 'object' const win = typeof window == 'object'
if (win && !window.VANTA) window.VANTA = {} if (win && !window.VANTA) {window.VANTA = {}}
const VANTA = (win && window.VANTA) || {} const VANTA = win && window.VANTA || {}
VANTA.register = (name, Effect) => { VANTA.register = (name, Effect) => {
return VANTA[name] = (opts) => new Effect(opts) return VANTA[name] = (opts) => new Effect(opts)
} }
@@ -11,7 +12,7 @@ VANTA.version = '0.5.21'
export { VANTA } export { VANTA }
import { AxisHelper, js, MOUSE, OrbitControls, Scene, WebGLRenderer } from 'three/src/Three' import { Scene, WebGLRenderer } from 'three/src/Three'
// const ORBITCONTROLS = { // const ORBITCONTROLS = {
// enableZoom: false, // enableZoom: false,
// userPanSpeed: 3, // userPanSpeed: 3,
@@ -40,7 +41,7 @@ const error = function() {
VANTA.VantaBase = class VantaBase { VANTA.VantaBase = class VantaBase {
constructor (userOptions = {}) { constructor (userOptions = {}) {
if (!win) return false if (!win) {return false}
VANTA.current = this VANTA.current = this
this.windowMouseMoveWrapper = this.windowMouseMoveWrapper.bind(this) this.windowMouseMoveWrapper = this.windowMouseMoveWrapper.bind(this)
this.windowTouchWrapper = this.windowTouchWrapper.bind(this) this.windowTouchWrapper = this.windowTouchWrapper.bind(this)
@@ -49,7 +50,7 @@ VANTA.VantaBase = class VantaBase {
this.animationLoop = this.animationLoop.bind(this) this.animationLoop = this.animationLoop.bind(this)
this.restart = this.restart.bind(this) this.restart = this.restart.bind(this)
const defaultOptions = (typeof this.getDefaultOptions === 'function') ? this.getDefaultOptions() : this.defaultOptions const defaultOptions = typeof this.getDefaultOptions === 'function' ? this.getDefaultOptions() : this.defaultOptions
this.options = extend({ this.options = extend({
mouseControls: true, mouseControls: true,
touchControls: true, touchControls: true,
@@ -68,12 +69,12 @@ VANTA.VantaBase = class VantaBase {
// Set element // Set element
this.el = this.options.el this.el = this.options.el
if (this.el == null) { if (this.el == null) {
error("Instance needs \"el\" param!") error('Instance needs "el" param!')
} else if (!(this.options.el instanceof HTMLElement)) { } else if (!(this.options.el instanceof HTMLElement)) {
const selector = this.el const selector = this.el
this.el = q(selector) this.el = q(selector)
if (!this.el) { if (!this.el) {
error("Cannot find element", selector) error('Cannot find element', selector)
return return
} }
} }
@@ -162,7 +163,7 @@ VANTA.VantaBase = class VantaBase {
zIndex: 0, zIndex: 0,
top: 0, top: 0,
left: 0, left: 0,
background: '' background: '',
}) })
extend(canvasEl.style, opts) extend(canvasEl.style, opts)
canvasEl.classList.add('vanta-canvas') canvasEl.classList.add('vanta-canvas')
@@ -170,13 +171,13 @@ VANTA.VantaBase = class VantaBase {
initThree () { initThree () {
if (!WebGLRenderer) { if (!WebGLRenderer) {
console.warn("[VANTA] No THREE defined on window") console.warn('[VANTA] No THREE defined on window')
return return
} }
// Set renderer // Set renderer
this.renderer = new WebGLRenderer({ this.renderer = new WebGLRenderer({
alpha: true, alpha: true,
antialias: true antialias: true,
}) })
this.el.appendChild(this.renderer.domElement) this.el.appendChild(this.renderer.domElement)
this.applyCanvasStyles(this.renderer.domElement) this.applyCanvasStyles(this.renderer.domElement)
@@ -198,43 +199,43 @@ VANTA.VantaBase = class VantaBase {
getCanvasRect () { getCanvasRect () {
const canvas = this.getCanvasElement() const canvas = this.getCanvasElement()
if (!canvas) return false if (!canvas) {return false}
return canvas.getBoundingClientRect() return canvas.getBoundingClientRect()
} }
windowMouseMoveWrapper (e){ windowMouseMoveWrapper (e){
const rect = this.getCanvasRect() const rect = this.getCanvasRect()
if (!rect) return false if (!rect) {return false}
const x = e.clientX - rect.left const x = e.clientX - rect.left
const y = e.clientY - rect.top const y = e.clientY - rect.top
if (x>=0 && y>=0 && x<=rect.width && y<=rect.height) { if (x>=0 && y>=0 && x<=rect.width && y<=rect.height) {
this.mouseX = x this.mouseX = x
this.mouseY = y this.mouseY = y
if (!this.options.mouseEase) this.triggerMouseMove(x, y) if (!this.options.mouseEase) {this.triggerMouseMove(x, y)}
} }
} }
windowTouchWrapper (e){ windowTouchWrapper (e){
const rect = this.getCanvasRect() const rect = this.getCanvasRect()
if (!rect) return false if (!rect) {return false}
if (e.touches.length === 1) { if (e.touches.length === 1) {
const x = e.touches[0].clientX - rect.left const x = e.touches[0].clientX - rect.left
const y = e.touches[0].clientY - rect.top const y = e.touches[0].clientY - rect.top
if (x>=0 && y>=0 && x<=rect.width && y<=rect.height) { if (x>=0 && y>=0 && x<=rect.width && y<=rect.height) {
this.mouseX = x this.mouseX = x
this.mouseY = y this.mouseY = y
if (!this.options.mouseEase) this.triggerMouseMove(x, y) if (!this.options.mouseEase) {this.triggerMouseMove(x, y)}
} }
} }
} }
windowGyroWrapper (e){ windowGyroWrapper (e){
const rect = this.getCanvasRect() const rect = this.getCanvasRect()
if (!rect) return false if (!rect) {return false}
const x = Math.round(e.alpha * 2) - rect.left const x = Math.round(e.alpha * 2) - rect.left
const y = Math.round(e.beta * 2) - rect.top const y = Math.round(e.beta * 2) - rect.top
if (x>=0 && y>=0 && x<=rect.width && y<=rect.height) { if (x>=0 && y>=0 && x<=rect.width && y<=rect.height) {
this.mouseX = x this.mouseX = x
this.mouseY = y this.mouseY = y
if (!this.options.mouseEase) this.triggerMouseMove(x, y) if (!this.options.mouseEase) {this.triggerMouseMove(x, y)}
} }
} }
@@ -254,7 +255,7 @@ VANTA.VantaBase = class VantaBase {
} }
const xNorm = x / this.width // 0 to 1 const xNorm = x / this.width // 0 to 1
const yNorm = y / this.height // 0 to 1 const yNorm = y / this.height // 0 to 1
typeof this.onMouseMove === "function" ? this.onMouseMove(xNorm, yNorm) : void 0 typeof this.onMouseMove === 'function' ? this.onMouseMove(xNorm, yNorm) : void 0
} }
setSize () { setSize () {
@@ -269,8 +270,8 @@ VANTA.VantaBase = class VantaBase {
} }
initMouse () { initMouse () {
// Init mouseX and mouseY // Init mouseX and mouseY
if ((!this.mouseX && !this.mouseY) || if (!this.mouseX && !this.mouseY ||
(this.mouseX === this.options.minWidth/2 && this.mouseY === this.options.minHeight/2)) { this.mouseX === this.options.minWidth/2 && this.mouseY === this.options.minHeight/2) {
this.mouseX = this.width/2 this.mouseX = this.width/2
this.mouseY = this.height/2 this.mouseY = this.height/2
this.triggerMouseMove(this.mouseX, this.mouseY) this.triggerMouseMove(this.mouseX, this.mouseY)
@@ -281,7 +282,7 @@ VANTA.VantaBase = class VantaBase {
this.setSize() this.setSize()
if (this.camera) { if (this.camera) {
this.camera.aspect = this.width / this.height this.camera.aspect = this.width / this.height
if (typeof this.camera.updateProjectionMatrix === "function") { if (typeof this.camera.updateProjectionMatrix === 'function') {
this.camera.updateProjectionMatrix() this.camera.updateProjectionMatrix()
} }
} }
@@ -289,15 +290,15 @@ VANTA.VantaBase = class VantaBase {
this.renderer.setSize(this.width, this.height) this.renderer.setSize(this.width, this.height)
this.renderer.setPixelRatio(window.devicePixelRatio / this.scale) this.renderer.setPixelRatio(window.devicePixelRatio / this.scale)
} }
typeof this.onResize === "function" ? this.onResize() : void 0 typeof this.onResize === 'function' ? this.onResize() : void 0
} }
isOnScreen () { isOnScreen () {
const elHeight = this.el.offsetHeight const elHeight = this.el.offsetHeight
const elRect = this.el.getBoundingClientRect() const elRect = this.el.getBoundingClientRect()
const scrollTop = (window.pageYOffset || const scrollTop = window.pageYOffset ||
(document.documentElement || document.body.parentNode || document.body).scrollTop (document.documentElement || document.body.parentNode || document.body).scrollTop
)
const offsetTop = elRect.top + scrollTop const offsetTop = elRect.top + scrollTop
const minScrollTop = offsetTop - window.innerHeight const minScrollTop = offsetTop - window.innerHeight
const maxScrollTop = offsetTop + elHeight const maxScrollTop = offsetTop + elHeight
@@ -310,7 +311,7 @@ VANTA.VantaBase = class VantaBase {
this.t += 1 this.t += 1
// Uniform time // Uniform time
this.t2 || (this.t2 = 0) this.t2 || (this.t2 = 0)
this.t2 += (this.options.speed || 1) this.t2 += this.options.speed || 1
if (this.uniforms) { if (this.uniforms) {
this.uniforms.iTime.value = this.t2 * 0.016667 // iTime is in seconds this.uniforms.iTime.value = this.t2 * 0.016667 // iTime is in seconds
} }
@@ -327,7 +328,7 @@ VANTA.VantaBase = class VantaBase {
// Only animate if element is within view // Only animate if element is within view
if (this.isOnScreen() || this.options.forceAnimate) { if (this.isOnScreen() || this.options.forceAnimate) {
if (typeof this.onUpdate === "function") { if (typeof this.onUpdate === 'function') {
this.onUpdate() this.onUpdate()
} }
if (this.scene && this.camera) { if (this.scene && this.camera) {
@@ -336,8 +337,8 @@ VANTA.VantaBase = class VantaBase {
} }
// if (this.stats) this.stats.update() // if (this.stats) this.stats.update()
// if (this.renderStats) this.renderStats.update(this.renderer) // if (this.renderStats) this.renderStats.update(this.renderer)
if (this.fps && this.fps.update) this.fps.update() if (this.fps && this.fps.update) {this.fps.update()}
if (typeof this.afterRender === "function") this.afterRender() if (typeof this.afterRender === 'function') {this.afterRender()}
} }
return this.req = window.requestAnimationFrame(this.animationLoop) return this.req = window.requestAnimationFrame(this.animationLoop)
} }
@@ -357,21 +358,21 @@ VANTA.VantaBase = class VantaBase {
this.scene.remove(this.scene.children[0]) this.scene.remove(this.scene.children[0])
} }
} }
if (typeof this.onRestart === "function") { if (typeof this.onRestart === 'function') {
this.onRestart() this.onRestart()
} }
this.init() this.init()
} }
init () { init () {
if (typeof this.onInit === "function") { if (typeof this.onInit === 'function') {
this.onInit() this.onInit()
} }
// this.setupControls() // this.setupControls()
} }
destroy () { destroy () {
if (typeof this.onDestroy === "function") { if (typeof this.onDestroy === 'function') {
this.onDestroy() this.onDestroy()
} }
const rm = window.removeEventListener const rm = window.removeEventListener

View File

@@ -1,6 +1,9 @@
/* eslint-disable @typescript-eslint/init-declarations */
/* eslint-disable @typescript-eslint/prefer-for-of */
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import VantaBase, { VANTA } from './_base' import VantaBase, { VANTA } from './_base'
import { rn, ri, sample } from 'vanta/src/helpers.js' import { rn, ri } from 'vanta/src/helpers.js'
import { Geometry, MeshPhongMaterial, Vector3, Face3, Mesh, AmbientLight, EdgesGeometry, LineBasicMaterial, LineSegments, PerspectiveCamera, PointLight, DoubleSide } from 'three/src/Three' import { Geometry, MeshPhongMaterial, Vector3, Face3, Mesh, AmbientLight, PerspectiveCamera, PointLight, DoubleSide } from 'three/src/Three'
import { FaceColors } from 'three/src/Three.Legacy' import { FaceColors } from 'three/src/Three.Legacy'
const defaultOptions = { const defaultOptions = {
@@ -8,17 +11,14 @@ const defaultOptions = {
shininess: 30, shininess: 30,
waveHeight: 15, waveHeight: 15,
waveSpeed: 1, waveSpeed: 1,
zoom: 1 zoom: 1,
} }
export class Waves extends VantaBase { export class Waves extends VantaBase {
static initClass () { static initClass () {
this.prototype.ww = 100; this.prototype.ww = 100
this.prototype.hh = 80; this.prototype.hh = 80
this.prototype.waveNoise = 4; // Choppiness of water this.prototype.waveNoise = 4 // Choppiness of water
}
constructor(userOptions) {
super(userOptions)
} }
getMaterial () { getMaterial () {
@@ -27,30 +27,30 @@ export class Waves extends VantaBase {
shininess: this.options.shininess, shininess: this.options.shininess,
flatShading: true, flatShading: true,
vertexColors: FaceColors, // Allow coloring individual faces vertexColors: FaceColors, // Allow coloring individual faces
side: DoubleSide side: DoubleSide,
}; }
return new MeshPhongMaterial(options); return new MeshPhongMaterial(options)
} }
onInit () { onInit () {
let i, j; let i, j
const CELLSIZE = 18; const CELLSIZE = 18
const material = this.getMaterial(); const material = this.getMaterial()
const geometry = new Geometry(); const geometry = new Geometry()
// Add vertices // Add vertices
this.gg = []; this.gg = []
for (i=0; i<=this.ww; i++){ for (i=0; i<=this.ww; i++){
this.gg[i] = []; this.gg[i] = []
for (j=0; j<=this.hh; j++){ for (j=0; j<=this.hh; j++){
const id = geometry.vertices.length; const id = geometry.vertices.length
const newVertex = new Vector3( const newVertex = new Vector3(
(i - (this.ww * 0.5)) * CELLSIZE, (i - this.ww * 0.5) * CELLSIZE,
rn(0, this.waveNoise) - 10, rn(0, this.waveNoise) - 10,
((this.hh * 0.5) - j) * CELLSIZE (this.hh * 0.5 - j) * CELLSIZE
); )
geometry.vertices.push(newVertex); geometry.vertices.push(newVertex)
this.gg[i][j] = id; this.gg[i][j] = id
} }
} }
@@ -75,8 +75,8 @@ export class Waves extends VantaBase {
} }
} }
this.plane = new Mesh(geometry, material); this.plane = new Mesh(geometry, material)
this.scene.add(this.plane); this.scene.add(this.plane)
// WIREFRAME // WIREFRAME
// lightColor = 0x55aaee // lightColor = 0x55aaee
@@ -88,55 +88,55 @@ export class Waves extends VantaBase {
// @scene.add( @wireframe ) // @scene.add( @wireframe )
// LIGHTS // LIGHTS
const ambience = new AmbientLight( 0xffffff, 0.9 ); const ambience = new AmbientLight( 0xffffff, 0.9 )
this.scene.add(ambience); this.scene.add(ambience)
const pointLight = new PointLight( 0xffffff, 0.9 ); const pointLight = new PointLight( 0xffffff, 0.9 )
pointLight.position.set(-100,250,-100); pointLight.position.set(-100, 250, -100)
this.scene.add(pointLight); this.scene.add(pointLight)
// CAMERA // CAMERA
this.camera = new PerspectiveCamera( this.camera = new PerspectiveCamera(
35, 35,
this.width / this.height, this.width / this.height,
50, 10000); 50, 10000)
const xOffset = -10; const xOffset = -10
const zOffset = -10; const zOffset = -10
this.cameraPosition = new Vector3( 250+xOffset, 200, 400+zOffset ); this.cameraPosition = new Vector3( 250+xOffset, 200, 400+zOffset )
this.cameraTarget = new Vector3( 150+xOffset, -30, 200+zOffset ); this.cameraTarget = new Vector3( 150+xOffset, -30, 200+zOffset )
this.camera.position.copy(this.cameraPosition); this.camera.position.copy(this.cameraPosition)
this.scene.add(this.camera); this.scene.add(this.camera)
} }
onUpdate () { onUpdate () {
// Update options // Update options
let diff; let diff
this.plane.material.color.set(this.options.color); this.plane.material.color.set(this.options.color)
this.plane.material.shininess = this.options.shininess; this.plane.material.shininess = this.options.shininess
this.camera.ox = this.cameraPosition.x / this.options.zoom; this.camera.ox = this.cameraPosition.x / this.options.zoom
this.camera.oy = this.cameraPosition.y / this.options.zoom; this.camera.oy = this.cameraPosition.y / this.options.zoom
this.camera.oz = this.cameraPosition.z / this.options.zoom; this.camera.oz = this.cameraPosition.z / this.options.zoom
if (this.controls != null) { if (this.controls != null) {
this.controls.update(); this.controls.update()
} }
const c = this.camera; const c = this.camera
if (Math.abs(c.tx - c.position.x) > 0.01) { if (Math.abs(c.tx - c.position.x) > 0.01) {
diff = c.tx - c.position.x; diff = c.tx - c.position.x
c.position.x += diff * 0.02; c.position.x += diff * 0.02
} }
if (Math.abs(c.ty - c.position.y) > 0.01) { if (Math.abs(c.ty - c.position.y) > 0.01) {
diff = c.ty - c.position.y; diff = c.ty - c.position.y
c.position.y += diff * 0.02; c.position.y += diff * 0.02
} }
if (Math.abs(c.tz - c.position.z) > 0.01) { if (Math.abs(c.tz - c.position.z) > 0.01) {
diff = c.tz - c.position.z; diff = c.tz - c.position.z
c.position.z += diff * 0.02; c.position.z += diff * 0.02
} }
c.lookAt( this.cameraTarget ); c.lookAt( this.cameraTarget )
// Fix flickering problems // Fix flickering problems
// c.near = Math.max((c.position.y * 0.5) - 20, 1); // c.near = Math.max((c.position.y * 0.5) - 20, 1);
@@ -144,24 +144,24 @@ export class Waves extends VantaBase {
// WAVES // WAVES
for (let i = 0; i < this.plane.geometry.vertices.length; i++) { for (let i = 0; i < this.plane.geometry.vertices.length; i++) {
const v = this.plane.geometry.vertices[i]; const v = this.plane.geometry.vertices[i]
if (!v.oy) { // INIT if (!v.oy) { // INIT
v.oy = v.y; v.oy = v.y
} else { } else {
const s = this.options.waveSpeed; const s = this.options.waveSpeed
const crossChop = Math.sqrt(s) * Math.cos(-v.x - (v.z*0.7)); // + s * (i % 229) / 229 * 5 const crossChop = Math.sqrt(s) * Math.cos(-v.x - v.z*0.7) // + s * (i % 229) / 229 * 5
const delta = Math.sin((((s*this.t*0.02) - (s*v.x*0.025)) + (s*v.z*0.015) + crossChop)); const delta = Math.sin(s*this.t*0.02 - s*v.x*0.025 + s*v.z*0.015 + crossChop)
const trochoidDelta = Math.pow(delta + 1, 2) / 4; const trochoidDelta = Math.pow(delta + 1, 2) / 4
v.y = v.oy + (trochoidDelta * this.options.waveHeight); v.y = v.oy + trochoidDelta * this.options.waveHeight
} }
} }
// @wireframe.geometry.vertices[i].y = v.y // @wireframe.geometry.vertices[i].y = v.y
this.plane.geometry.dynamic = true; this.plane.geometry.dynamic = true
this.plane.geometry.computeFaceNormals(); this.plane.geometry.computeFaceNormals()
this.plane.geometry.verticesNeedUpdate = true; this.plane.geometry.verticesNeedUpdate = true
this.plane.geometry.normalsNeedUpdate = true; this.plane.geometry.normalsNeedUpdate = true
// @scene.remove( @wireframe ) // @scene.remove( @wireframe )
// geo = new EdgesGeometry(@plane.geometry) // geo = new EdgesGeometry(@plane.geometry)
@@ -170,21 +170,21 @@ export class Waves extends VantaBase {
// @scene.add( @wireframe ) // @scene.add( @wireframe )
if (this.wireframe) { if (this.wireframe) {
this.wireframe.geometry.fromGeometry(this.plane.geometry); this.wireframe.geometry.fromGeometry(this.plane.geometry)
this.wireframe.geometry.computeFaceNormals(); this.wireframe.geometry.computeFaceNormals()
} }
} }
onMouseMove (x, y) { onMouseMove (x, y) {
const c = this.camera; const c = this.camera
if (!c.oy) { if (!c.oy) {
c.oy = c.position.y; c.oy = c.position.y
c.ox = c.position.x; c.ox = c.position.x
c.oz = c.position.z; c.oz = c.position.z
} }
c.tx = c.ox + (((x-0.5) * 100) / this.options.zoom); c.tx = c.ox + (x-0.5) * 100 / this.options.zoom
c.ty = c.oy + (((y-0.5) * -100) / this.options.zoom); c.ty = c.oy + (y-0.5) * -100 / this.options.zoom
return c.tz = c.oz + (((x-0.5) * -50) / this.options.zoom); return c.tz = c.oz + (x-0.5) * -50 / this.options.zoom
} }
} }

View File

@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-extraneous-class */
import { NgModule } from '@angular/core' import { NgModule } from '@angular/core'
import { NgbNavModule } from '@ng-bootstrap/ng-bootstrap' import { NgbNavModule } from '@ng-bootstrap/ng-bootstrap'
import { CommonModule } from '@angular/common' import { CommonModule } from '@angular/common'

View File

@@ -30,7 +30,7 @@ const hardlinks = {
function start () { function start () {
const app = express() const app = express()
const PORT = process.env.PORT || 8000 const PORT = process.env.PORT ?? 8000
const DIST_FOLDER = join(process.cwd(), 'build') const DIST_FOLDER = join(process.cwd(), 'build')
app.engine('html', engine) app.engine('html', engine)
@@ -48,12 +48,17 @@ function start () {
{ {
req, req,
providers: [ providers: [
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
{ provide: 'BACKEND_URL', useValue: process.env.BACKEND_URL ?? '' }, { provide: 'BACKEND_URL', useValue: process.env.BACKEND_URL ?? '' },
], ],
}, },
(err: Error, html: string) => { (err?: Error, html?: string) => {
if (html) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
html = html.replace('{{backendURL}}', process.env.BACKEND_URL ?? '') html = html.replace('{{backendURL}}', process.env.BACKEND_URL ?? '')
res.status(err ? 500 : 200).send(html || err.message) }
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
res.status(err ? 500 : 200).send(html ?? err!.message)
}, },
) )
}) })
@@ -72,7 +77,7 @@ function start () {
}) })
} }
const WORKERS = process.env.WEB_CONCURRENCY || 4 const WORKERS = process.env.WEB_CONCURRENCY ?? 4
throng({ throng({
workers: WORKERS, workers: WORKERS,
lifetime: Infinity, lifetime: Infinity,

View File

@@ -1,41 +1,41 @@
import * as domino from 'domino'; import * as domino from 'domino'
import * as fs from 'fs'; import * as fs from 'fs'
import * as path from 'path'; import * as path from 'path'
const template = fs.readFileSync(path.join(process.cwd(), 'build', 'index.html')).toString(); const template = fs.readFileSync(path.join(process.cwd(), 'build', 'index.html')).toString()
const win = domino.createWindow(template); const win = domino.createWindow(template)
global['window'] = win; global['window'] = win
Object.defineProperty(win.document.body.style, 'transform', { Object.defineProperty(win.document.body.style, 'transform', {
value: () => { value: () => {
return { return {
enumerable: true, enumerable: true,
configurable: true configurable: true,
}; }
}, },
}); })
Object.defineProperty(win.document.body.style, 'z-index', { Object.defineProperty(win.document.body.style, 'z-index', {
value: () => { value: () => {
return { return {
enumerable: true, enumerable: true,
configurable: true configurable: true,
}; }
}, },
}); })
global['document'] = win.document; global['document'] = win.document
global['CSS'] = null; global['CSS'] = null
// global['atob'] = win.atob; // global['atob'] = win.atob;
global['atob'] = (base64: string) => { global['atob'] = (base64: string) => {
return Buffer.from(base64, 'base64').toString(); return Buffer.from(base64, 'base64').toString()
}; }
function setDomTypes () { function setDomTypes () {
// Make all Domino types available as types in the global env. // Make all Domino types available as types in the global env.
Object.assign(global, domino['impl']); Object.assign(global, domino['impl']);
(global as any)['KeyboardEvent'] = domino['impl'].Event; (global as any)['KeyboardEvent'] = domino['impl'].Event
} }
setDomTypes(); setDomTypes()

View File

@@ -24,7 +24,7 @@ async function start () {
await new Promise(resolve => { await new Promise(resolve => {
e.onload = resolve e.onload = resolve
e.src = url e.src = url
document.querySelector('head').appendChild(e) document.head.appendChild(e)
}) })
return window['module'].exports return window['module'].exports
} }
@@ -45,7 +45,7 @@ async function start () {
await webRequire(url) await webRequire(url)
} }
document.querySelector('app-root')['style'].display = 'flex' document.querySelector('app-root')!['style'].display = 'flex'
const tabby = window['Tabby'] const tabby = window['Tabby']

View File

@@ -17,6 +17,7 @@
"esModuleInterop": true, "esModuleInterop": true,
"allowSyntheticDefaultImports": true, "allowSyntheticDefaultImports": true,
"declaration": true, "declaration": true,
"strictNullChecks": true,
"lib": [ "lib": [
"dom", "dom",
"es5", "es5",

View File

@@ -481,11 +481,16 @@
resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.2.tgz#693b316ad323ea97eed6b38ed1a3cc02b1672b57" resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.2.tgz#693b316ad323ea97eed6b38ed1a3cc02b1672b57"
integrity sha512-h4lTMgMJctJybDp8CQrxTUiiYmedihHWkjnF/8Pxseu2S6Nlfcy8kwboQ8yejh456rP2yWoEVm1sS/FVsfM48w== integrity sha512-h4lTMgMJctJybDp8CQrxTUiiYmedihHWkjnF/8Pxseu2S6Nlfcy8kwboQ8yejh456rP2yWoEVm1sS/FVsfM48w==
"@types/json-schema@*", "@types/json-schema@^7.0.7", "@types/json-schema@^7.0.8": "@types/json-schema@*", "@types/json-schema@^7.0.8":
version "7.0.8" version "7.0.8"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.8.tgz#edf1bf1dbf4e04413ca8e5b17b3b7d7d54b59818" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.8.tgz#edf1bf1dbf4e04413ca8e5b17b3b7d7d54b59818"
integrity sha512-YSBPTLTVm2e2OoQIDYx8HaeWJ5tTToLH67kXR7zYNGupXMEHa2++G8k+DczX2cFVgalypqtyZIcU19AFcmOpmg== integrity sha512-YSBPTLTVm2e2OoQIDYx8HaeWJ5tTToLH67kXR7zYNGupXMEHa2++G8k+DczX2cFVgalypqtyZIcU19AFcmOpmg==
"@types/json-schema@^7.0.9":
version "7.0.9"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d"
integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==
"@types/node@*": "@types/node@*":
version "16.4.2" version "16.4.2"
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.4.2.tgz#0a95d7fd950cb1eaca0ce11031d72e8f680b775a" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.4.2.tgz#0a95d7fd950cb1eaca0ce11031d72e8f680b775a"
@@ -496,74 +501,75 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-11.9.5.tgz#011eece9d3f839a806b63973e228f85967b79ed3" resolved "https://registry.yarnpkg.com/@types/node/-/node-11.9.5.tgz#011eece9d3f839a806b63973e228f85967b79ed3"
integrity sha512-vVjM0SVzgaOUpflq4GYBvCpozes8OgIIS5gVXVka+OfK3hvnkC1i93U8WiY2OtNE4XUWyyy/86Kf6e0IHTQw1Q== integrity sha512-vVjM0SVzgaOUpflq4GYBvCpozes8OgIIS5gVXVka+OfK3hvnkC1i93U8WiY2OtNE4XUWyyy/86Kf6e0IHTQw1Q==
"@typescript-eslint/eslint-plugin@^4.28.4": "@typescript-eslint/eslint-plugin@^5.1.0":
version "4.28.4" version "5.1.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.28.4.tgz#e73c8cabbf3f08dee0e1bda65ed4e622ae8f8921" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.1.0.tgz#381c188dfab12f7a2c7b6a8ba2402d6273eadeaa"
integrity sha512-s1oY4RmYDlWMlcV0kKPBaADn46JirZzvvH7c2CtAqxCY96S538JRBAzt83RrfkDheV/+G/vWNK0zek+8TB3Gmw== integrity sha512-bekODL3Tqf36Yz8u+ilha4zGxL9mdB6LIsIoMAvvC5FAuWo4NpZYXtCbv7B2CeR1LhI/lLtLk+q4tbtxuoVuCg==
dependencies: dependencies:
"@typescript-eslint/experimental-utils" "4.28.4" "@typescript-eslint/experimental-utils" "5.1.0"
"@typescript-eslint/scope-manager" "4.28.4" "@typescript-eslint/scope-manager" "5.1.0"
debug "^4.3.1" debug "^4.3.2"
functional-red-black-tree "^1.0.1" functional-red-black-tree "^1.0.1"
regexpp "^3.1.0" ignore "^5.1.8"
regexpp "^3.2.0"
semver "^7.3.5" semver "^7.3.5"
tsutils "^3.21.0" tsutils "^3.21.0"
"@typescript-eslint/experimental-utils@4.28.4": "@typescript-eslint/experimental-utils@5.1.0":
version "4.28.4" version "5.1.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.28.4.tgz#9c70c35ebed087a5c70fb0ecd90979547b7fec96" resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.1.0.tgz#918a1a3d30404cc1f8edcfdf0df200804ef90d31"
integrity sha512-OglKWOQRWTCoqMSy6pm/kpinEIgdcXYceIcH3EKWUl4S8xhFtN34GQRaAvTIZB9DD94rW7d/U7tUg3SYeDFNHA== integrity sha512-ovE9qUiZMOMgxQAESZsdBT+EXIfx/YUYAbwGUI6V03amFdOOxI9c6kitkgRvLkJaLusgMZ2xBhss+tQ0Y1HWxA==
dependencies: dependencies:
"@types/json-schema" "^7.0.7" "@types/json-schema" "^7.0.9"
"@typescript-eslint/scope-manager" "4.28.4" "@typescript-eslint/scope-manager" "5.1.0"
"@typescript-eslint/types" "4.28.4" "@typescript-eslint/types" "5.1.0"
"@typescript-eslint/typescript-estree" "4.28.4" "@typescript-eslint/typescript-estree" "5.1.0"
eslint-scope "^5.1.1" eslint-scope "^5.1.1"
eslint-utils "^3.0.0" eslint-utils "^3.0.0"
"@typescript-eslint/parser@^4.28.4": "@typescript-eslint/parser@^5.1.0":
version "4.28.4" version "5.1.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.28.4.tgz#bc462dc2779afeefdcf49082516afdc3e7b96fab" resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.1.0.tgz#6c7f837d210d2bc0a811e7ea742af414f4e00908"
integrity sha512-4i0jq3C6n+og7/uCHiE6q5ssw87zVdpUj1k6VlVYMonE3ILdFApEzTWgppSRG4kVNB/5jxnH+gTeKLMNfUelQA== integrity sha512-vx1P+mhCtYw3+bRHmbalq/VKP2Y3gnzNgxGxfEWc6OFpuEL7iQdAeq11Ke3Rhy8NjgB+AHsIWEwni3e+Y7djKA==
dependencies: dependencies:
"@typescript-eslint/scope-manager" "4.28.4" "@typescript-eslint/scope-manager" "5.1.0"
"@typescript-eslint/types" "4.28.4" "@typescript-eslint/types" "5.1.0"
"@typescript-eslint/typescript-estree" "4.28.4" "@typescript-eslint/typescript-estree" "5.1.0"
debug "^4.3.1" debug "^4.3.2"
"@typescript-eslint/scope-manager@4.28.4": "@typescript-eslint/scope-manager@5.1.0":
version "4.28.4" version "5.1.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.28.4.tgz#bdbce9b6a644e34f767bd68bc17bb14353b9fe7f" resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.1.0.tgz#6f1f26ad66a8f71bbb33b635e74fec43f76b44df"
integrity sha512-ZJBNs4usViOmlyFMt9X9l+X0WAFcDH7EdSArGqpldXu7aeZxDAuAzHiMAeI+JpSefY2INHrXeqnha39FVqXb8w== integrity sha512-yYlyVjvn5lvwCL37i4hPsa1s0ORsjkauhTqbb8MnpvUs7xykmcjGqwlNZ2Q5QpoqkJ1odlM2bqHqJwa28qV6Tw==
dependencies: dependencies:
"@typescript-eslint/types" "4.28.4" "@typescript-eslint/types" "5.1.0"
"@typescript-eslint/visitor-keys" "4.28.4" "@typescript-eslint/visitor-keys" "5.1.0"
"@typescript-eslint/types@4.28.4": "@typescript-eslint/types@5.1.0":
version "4.28.4" version "5.1.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.28.4.tgz#41acbd79b5816b7c0dd7530a43d97d020d3aeb42" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.1.0.tgz#a8a75ddfc611660de6be17d3ad950302385607a9"
integrity sha512-3eap4QWxGqkYuEmVebUGULMskR6Cuoc/Wii0oSOddleP4EGx1tjLnZQ0ZP33YRoMDCs5O3j56RBV4g14T4jvww== integrity sha512-sEwNINVxcB4ZgC6Fe6rUyMlvsB2jvVdgxjZEjQUQVlaSPMNamDOwO6/TB98kFt4sYYfNhdhTPBEQqNQZjMMswA==
"@typescript-eslint/typescript-estree@4.28.4": "@typescript-eslint/typescript-estree@5.1.0":
version "4.28.4" version "5.1.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.28.4.tgz#252e6863278dc0727244be9e371eb35241c46d00" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.1.0.tgz#132aea34372df09decda961cb42457433aa6e83d"
integrity sha512-z7d8HK8XvCRyN2SNp+OXC2iZaF+O2BTquGhEYLKLx5k6p0r05ureUtgEfo5f6anLkhCxdHtCf6rPM1p4efHYDQ== integrity sha512-SSz+l9YrIIsW4s0ZqaEfnjl156XQ4VRmJsbA0ZE1XkXrD3cRpzuZSVCyqeCMR3EBjF27IisWakbBDGhGNIOvfQ==
dependencies: dependencies:
"@typescript-eslint/types" "4.28.4" "@typescript-eslint/types" "5.1.0"
"@typescript-eslint/visitor-keys" "4.28.4" "@typescript-eslint/visitor-keys" "5.1.0"
debug "^4.3.1" debug "^4.3.2"
globby "^11.0.3" globby "^11.0.4"
is-glob "^4.0.1" is-glob "^4.0.3"
semver "^7.3.5" semver "^7.3.5"
tsutils "^3.21.0" tsutils "^3.21.0"
"@typescript-eslint/visitor-keys@4.28.4": "@typescript-eslint/visitor-keys@5.1.0":
version "4.28.4" version "5.1.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.28.4.tgz#92dacfefccd6751cbb0a964f06683bfd72d0c4d3" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.1.0.tgz#e01a01b27eb173092705ae983aa1451bd1842630"
integrity sha512-NIAXAdbz1XdOuzqkJHjNKXKj8QQ4cv5cxR/g0uQhCYf/6//XrmfpaYsM7PnBcNbfvTDLUkqQ5TPNm1sozDdTWg== integrity sha512-uqNXepKBg81JVwjuqAxYrXa1Ql/YDzM+8g/pS+TCPxba0wZttl8m5DkrasbfnmJGHs4lQ2jTbcZ5azGhI7kK+w==
dependencies: dependencies:
"@typescript-eslint/types" "4.28.4" "@typescript-eslint/types" "5.1.0"
eslint-visitor-keys "^2.0.0" eslint-visitor-keys "^3.0.0"
"@webassemblyjs/ast@1.11.1": "@webassemblyjs/ast@1.11.1":
version "1.11.1" version "1.11.1"
@@ -1508,7 +1514,7 @@ debug@2.6.9:
dependencies: dependencies:
ms "2.0.0" ms "2.0.0"
debug@^4.0.1, debug@^4.1.1, debug@^4.3.1: debug@^4.0.1, debug@^4.1.1, debug@^4.3.2:
version "4.3.2" version "4.3.2"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b"
integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==
@@ -1791,6 +1797,11 @@ eslint-visitor-keys@^2.0.0:
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303"
integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==
eslint-visitor-keys@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.0.0.tgz#e32e99c6cdc2eb063f204eda5db67bfe58bb4186"
integrity sha512-mJOZa35trBTb3IyRmo8xmKBZlxf+N7OnUl4+ZhJHs/r+0770Wh/LEACE2pqMGMe27G/4y8P2bYGk4J70IC5k1Q==
eslint@^7.31.0: eslint@^7.31.0:
version "7.31.0" version "7.31.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.31.0.tgz#f972b539424bf2604907a970860732c5d99d3aca" resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.31.0.tgz#f972b539424bf2604907a970860732c5d99d3aca"
@@ -2231,7 +2242,7 @@ globals@^13.6.0, globals@^13.9.0:
dependencies: dependencies:
type-fest "^0.20.2" type-fest "^0.20.2"
globby@^11.0.3: globby@^11.0.4:
version "11.0.4" version "11.0.4"
resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5"
integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==
@@ -2423,7 +2434,7 @@ ignore@^4.0.6:
resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==
ignore@^5.1.4: ignore@^5.1.4, ignore@^5.1.8:
version "5.1.8" version "5.1.8"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57"
integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==
@@ -2565,6 +2576,13 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1:
dependencies: dependencies:
is-extglob "^2.1.1" is-extglob "^2.1.1"
is-glob@^4.0.3:
version "4.0.3"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
dependencies:
is-extglob "^2.1.1"
is-number@^7.0.0: is-number@^7.0.0:
version "7.0.0" version "7.0.0"
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
@@ -3879,7 +3897,7 @@ regenerator-runtime@^0.11.0:
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
regexpp@^3.1.0: regexpp@^3.1.0, regexpp@^3.2.0:
version "3.2.0" version "3.2.0"
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2"
integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==