diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..92bd33894e --- /dev/null +++ b/.dockerignore @@ -0,0 +1,9 @@ +packages/server/node_modules +packages/builder +packages/frontend-core +packages/backend-core +packages/worker/node_modules +packages/cli +packages/client +packages/bbui +packages/string-templates diff --git a/.eslintrc.json b/.eslintrc.json index 8f4f68036b..87f8269c50 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -24,6 +24,22 @@ { "files": ["*.svelte"], "processor": "svelte3/svelte3" + }, + { + "files": ["**/*.ts"], + "parser": "@typescript-eslint/parser", + "plugins": [], + "extends": [ + "eslint:recommended" + ], + "rules": { + "no-unused-vars": "off", + "no-inner-declarations": "off", + "no-case-declarations": "off", + "no-useless-escape": "off", + "no-undef": "off", + "no-prototype-builtins": "off" + } } ], "rules": { diff --git a/.github/workflows/smoke_test.yaml b/.github/workflows/smoke_test.yaml index 745fed1306..b26d0386fc 100644 --- a/.github/workflows/smoke_test.yaml +++ b/.github/workflows/smoke_test.yaml @@ -2,6 +2,8 @@ name: Budibase Smoke Test on: workflow_dispatch: + schedule: + - cron: "0 5 * * *" # every day at 5AM jobs: release: @@ -23,10 +25,14 @@ jobs: -o packages/builder/cypress.env.json \ -L https://api.github.com/repos/budibase/budibase-infra/contents/test/cypress.env.json wc -l packages/builder/cypress.env.json - - run: yarn test:e2e:ci - env: - CI: true - name: Budibase CI + + - name: Cypress run + id: cypress + continue-on-error: true + uses: cypress-io/github-action@v2 + with: + install: false + command: yarn test:e2e:ci # TODO: upload recordings to s3 # - name: Configure AWS Credentials @@ -36,11 +42,11 @@ jobs: # aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} # aws-region: eu-west-1 - # TODO look at cypress reporters - # - name: Discord Webhook Action - # uses: tsickert/discord-webhook@v4.0.0 - # with: - # webhook-url: ${{ secrets.PROD_DEPLOY_WEBHOOK_URL }} - # content: "Production Deployment Complete: ${{ env.RELEASE_VERSION }} deployed to Budibase Cloud." - # embed-title: ${{ env.RELEASE_VERSION }} + - name: Discord Webhook Action + uses: tsickert/discord-webhook@v4.0.0 + with: + webhook-url: ${{ secrets.BUDI_QA_WEBHOOK }} + content: "Smoke test run completed with ${{ steps.cypress.outcome }}. See results at ${{ steps.cypress.dashboardUrl }}" + embed-title: ${{ steps.cypress.outcome }} + embed-color: ${{ steps.cypress.outcome == 'success' && '3066993' || '15548997' }} diff --git a/.vscode/launch.json b/.vscode/launch.json index 34951b6310..8cb49d5825 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -22,9 +22,16 @@ "name": "Budibase Worker", "type": "node", "request": "launch", - "program": "${workspaceFolder}/packages/worker/src/index.js", + "runtimeArgs": [ + "--nolazy", + "-r", + "ts-node/register/transpile-only" + ], + "args": [ + "${workspaceFolder}/packages/worker/src/index.ts" + ], "cwd": "${workspaceFolder}/packages/worker" - } + }, ], "compounds": [ { diff --git a/charts/budibase/Chart.yaml b/charts/budibase/Chart.yaml index daf8dad635..134d29441f 100644 --- a/charts/budibase/Chart.yaml +++ b/charts/budibase/Chart.yaml @@ -15,7 +15,7 @@ version: 0.2.8 appVersion: 1.0.48 dependencies: - name: couchdb - version: 3.3.4 + version: 3.6.1 repository: https://apache.github.io/couchdb-helm condition: services.couchdb.enabled - name: ingress-nginx diff --git a/charts/budibase/templates/app-service-deployment.yaml b/charts/budibase/templates/app-service-deployment.yaml index e263a7023d..d80d213416 100644 --- a/charts/budibase/templates/app-service-deployment.yaml +++ b/charts/budibase/templates/app-service-deployment.yaml @@ -106,6 +106,10 @@ spec: value: {{ .Values.globals.cookieDomain | quote }} - name: HTTP_MIGRATIONS value: {{ .Values.globals.httpMigrations | quote }} + - name: GOOGLE_CLIENT_ID + value: {{ .Values.globals.google.clientId | quote }} + - name: GOOGLE_CLIENT_SECRET + value: {{ .Values.globals.google.secret | quote }} image: budibase/apps:{{ .Values.globals.appVersion }} imagePullPolicy: Always name: bbapps diff --git a/examples/nextjs-api-sales/yarn.lock b/examples/nextjs-api-sales/yarn.lock index 3f32417ba8..52c89967b2 100644 --- a/examples/nextjs-api-sales/yarn.lock +++ b/examples/nextjs-api-sales/yarn.lock @@ -1894,9 +1894,9 @@ minimist-options@4.1.0: kind-of "^6.0.3" minimist@^1.2.0: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== minipass-collect@^1.0.2: version "1.0.2" diff --git a/hosting/docker-compose.dev.yaml b/hosting/docker-compose.dev.yaml index df403c0a22..43b8526e9e 100644 --- a/hosting/docker-compose.dev.yaml +++ b/hosting/docker-compose.dev.yaml @@ -5,7 +5,7 @@ version: "3" services: minio-service: container_name: budi-minio-dev - restart: always + restart: on-failure image: minio/minio volumes: - minio_data:/data @@ -23,7 +23,7 @@ services: proxy-service: container_name: budi-nginx-dev - restart: always + restart: on-failure image: nginx:latest volumes: - ./.generated-nginx.dev.conf:/etc/nginx/nginx.conf @@ -38,7 +38,7 @@ services: couchdb-service: # platform: linux/amd64 container_name: budi-couchdb-dev - restart: always + restart: on-failure image: ibmcom/couchdb3 environment: - COUCHDB_PASSWORD=${COUCH_DB_PASSWORD} @@ -59,7 +59,7 @@ services: redis-service: container_name: budi-redis-dev - restart: always + restart: on-failure image: redis command: redis-server --requirepass ${REDIS_PASSWORD} ports: diff --git a/hosting/docker-compose.yaml b/hosting/docker-compose.yaml index 8143be54b7..f9d9eaf1c5 100644 --- a/hosting/docker-compose.yaml +++ b/hosting/docker-compose.yaml @@ -4,7 +4,7 @@ version: "3" services: app-service: - restart: always + restart: unless-stopped image: budibase.docker.scarf.sh/budibase/apps container_name: bbapps environment: @@ -28,7 +28,7 @@ services: - redis-service worker-service: - restart: always + restart: unless-stopped image: budibase.docker.scarf.sh/budibase/worker container_name: bbworker environment: @@ -53,7 +53,7 @@ services: - couch-init minio-service: - restart: always + restart: unless-stopped image: minio/minio volumes: - minio_data:/data @@ -69,7 +69,7 @@ services: retries: 3 proxy-service: - restart: always + restart: unless-stopped ports: - "${MAIN_PORT}:10000" container_name: bbproxy @@ -81,7 +81,7 @@ services: - couchdb-service couchdb-service: - restart: always + restart: unless-stopped image: ibmcom/couchdb3 environment: - COUCHDB_PASSWORD=${COUCH_DB_PASSWORD} @@ -98,13 +98,14 @@ services: command: ["sh","-c","sleep 10 && $${PUT_CALL}/_users && $${PUT_CALL}/_replicator; fg;"] redis-service: - restart: always + restart: unless-stopped image: redis command: redis-server --requirepass ${REDIS_PASSWORD} volumes: - redis_data:/data watchtower-service: + restart: always image: containrrr/watchtower volumes: - /var/run/docker.sock:/var/run/docker.sock @@ -116,7 +117,6 @@ services: labels: - "com.centurylinklabs.watchtower.enable=false" - volumes: couchdb3_data: driver: local diff --git a/hosting/nginx.dev.conf.hbs b/hosting/nginx.dev.conf.hbs index 441fffa9f7..9fc2345fb2 100644 --- a/hosting/nginx.dev.conf.hbs +++ b/hosting/nginx.dev.conf.hbs @@ -52,9 +52,8 @@ http { proxy_pass http://{{ address }}:4001; } - location /app/ { + location /app { proxy_pass http://{{ address }}:4001; - rewrite ^/app/(.*)$ /$1 break; } location /builder { diff --git a/hosting/nginx.prod.conf.hbs b/hosting/nginx.prod.conf.hbs index f3009baf40..88570a4a2d 100644 --- a/hosting/nginx.prod.conf.hbs +++ b/hosting/nginx.prod.conf.hbs @@ -22,9 +22,8 @@ http { resolver {{ resolver }} valid=10s ipv6=off; # buffering - client_body_buffer_size 1K; client_header_buffer_size 1k; - client_max_body_size 10M; + client_max_body_size 20M; ignore_invalid_headers off; proxy_buffering off; @@ -43,13 +42,25 @@ http { client_max_body_size 1000m; ignore_invalid_headers off; proxy_buffering off; - # port_in_redirect off; + + set $csp_default "default-src 'self'"; + set $csp_script "script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.budi.live https://js.intercomcdn.com https://widget.intercom.io"; + set $csp_style "style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://fonts.googleapis.com https://rsms.me https://maxcdn.bootstrapcdn.com"; + set $csp_object "object-src 'none'"; + set $csp_base_uri "base-uri 'self'"; + set $csp_connect "connect-src 'self' https://api-iam.intercom.io https://api-iam.intercom.io https://api-ping.intercom.io https://app.posthog.com wss://nexus-websocket-a.intercom.io wss://nexus-websocket-b.intercom.io https://nexus-websocket-a.intercom.io https://nexus-websocket-b.intercom.io https://uploads.intercomcdn.com https://uploads.intercomusercontent.com"; + set $csp_font "font-src 'self' data: https://cdn.jsdelivr.net https://fonts.gstatic.com https://rsms.me https://maxcdn.bootstrapcdn.com https://js.intercomcdn.com https://fonts.intercomcdn.com"; + set $csp_frame "frame-src 'self' https:"; + set $csp_img "img-src http: https: data: blob:"; + set $csp_manifest "manifest-src 'self'"; + set $csp_media "media-src 'self' https://js.intercomcdn.com"; + set $csp_worker "worker-src 'none'"; # Security Headers add_header X-Frame-Options SAMEORIGIN always; add_header X-Content-Type-Options nosniff always; add_header X-XSS-Protection "1; mode=block" always; - add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.budi.live https://js.intercomcdn.com https://widget.intercom.io; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://fonts.googleapis.com https://rsms.me https://maxcdn.bootstrapcdn.com; object-src 'none'; base-uri 'self'; connect-src 'self' https://api-iam.intercom.io https://app.posthog.com wss://nexus-websocket-a.intercom.io ; font-src 'self' data https://cdn.jsdelivr.net https://fonts.gstatic.com https://rsms.me https://maxcdn.bootstrapcdn.com; frame-src 'self' https:; img-src http: https: data; manifest-src 'self'; media-src 'self'; worker-src 'none';" always; + add_header Content-Security-Policy "${csp_default}; ${csp_script}; ${csp_style}; ${csp_object}; ${csp_base_uri}; ${csp_connect}; ${csp_font}; ${csp_frame}; ${csp_img}; ${csp_manifest}; ${csp_media}; ${csp_worker};" always; # upstreams set $apps {{ apps }}; @@ -62,7 +73,6 @@ http { location /app { proxy_pass http://$apps:4002; - rewrite ^/app/(.*)$ /$1 break; } location = / { diff --git a/hosting/portainer/template.json b/hosting/portainer/template.json new file mode 100644 index 0000000000..29107b674e --- /dev/null +++ b/hosting/portainer/template.json @@ -0,0 +1,94 @@ +{ + "version": "2", + "templates": [ + { + "type": 3, + "title": "Budibase", + "categories": ["Tools"], + "description": "Build modern business apps in minutes", + "logo": "https://budibase.com/favicon.ico", + "platform": "linux", + "repository": { + "url": "https://github.com/Budibase/budibase", + "stackfile": "hosting/docker-compose.yaml" + }, + "env": [ + { + "name": "MAIN_PORT", + "label": "Main port", + "default": "10000" + }, + { + "name": "JWT_SECRET", + "label": "JWT secret", + "default": "change-me" + }, + { + "name": "MINIO_ACCESS_KEY", + "label": "MinIO access key", + "default": "change-me" + }, + { + "name": "MINIO_SECRET_KEY", + "label": "MinIO secret key", + "default": "change-me" + }, + { + "name": "COUCH_DB_USER", + "default": "budibase", + "preset": true + }, + { + "name": "COUCH_DB_PASSWORD", + "label": "Couch DB password", + "default": "change-me" + }, + { + "name": "REDIS_PASSWORD", + "label": "Redis password", + "default": "change-me" + }, + { + "name": "INTERNAL_API_KEY", + "label": "Internal API key", + "default": "change-me" + }, + { + "name": "APP_PORT", + "default": "4002", + "preset": true + }, + { + "name": "WORKER_PORT", + "default": "4003", + "preset": true + }, + { + "name": "MINIO_PORT", + "default": "4004", + "preset": true + }, + { + "name": "COUCH_DB_PORT", + "default": "4005", + "preset": true + }, + { + "name": "REDIS_PORT", + "default": "6379", + "preset": true + }, + { + "name": "WATCHTOWER_PORT", + "default": "6161", + "preset": true + }, + { + "name": "BUDIBASE_ENVIRONMENT", + "default": "PRODUCTION", + "preset": true + } + ] + } + ] +} diff --git a/hosting/single/Dockerfile b/hosting/single/Dockerfile new file mode 100644 index 0000000000..2123d237b5 --- /dev/null +++ b/hosting/single/Dockerfile @@ -0,0 +1,97 @@ +FROM couchdb + +ENV COUCHDB_PASSWORD=budibase +ENV COUCHDB_USER=budibase +ENV COUCH_DB_URL=http://budibase:budibase@localhost:5984 +ENV BUDIBASE_ENVIRONMENT=PRODUCTION +ENV MINIO_URL=http://localhost:9000 +ENV REDIS_URL=localhost:6379 +ENV WORKER_URL=http://localhost:4002 +ENV INTERNAL_API_KEY=budibase +ENV JWT_SECRET=testsecret +ENV MINIO_ACCESS_KEY=budibase +ENV MINIO_SECRET_KEY=budibase +ENV SELF_HOSTED=1 +ENV CLUSTER_PORT=10000 +ENV REDIS_PASSWORD=budibase +ENV ARCHITECTURE=amd +ENV APP_PORT=4001 +ENV WORKER_PORT=4002 + +RUN apt-get update +RUN apt-get install software-properties-common wget nginx -y +RUN apt-add-repository 'deb http://security.debian.org/debian-security stretch/updates main' +RUN apt-get update + +# setup nginx +ADD hosting/single/nginx.conf /etc/nginx +RUN mkdir /etc/nginx/logs +RUN useradd www +RUN touch /etc/nginx/logs/error.log +RUN touch /etc/nginx/logs/nginx.pid + +# install java +RUN apt-get install openjdk-8-jdk -y + +# setup nodejs +WORKDIR /nodejs +RUN curl -sL https://deb.nodesource.com/setup_16.x -o /tmp/nodesource_setup.sh +RUN bash /tmp/nodesource_setup.sh +RUN apt-get install nodejs +RUN npm install --global yarn +RUN npm install --global pm2 + +# setup redis +RUN apt install redis-server -y + +# setup server +WORKDIR /app +ADD packages/server . +RUN ls -al +RUN yarn +RUN yarn build +# Install client for oracle datasource +RUN apt-get install unzip libaio1 +RUN /bin/bash -e scripts/integrations/oracle/instantclient/linux/x86-64/install.sh + +# setup worker +WORKDIR /worker +ADD packages/worker . +RUN yarn +RUN yarn build + +# setup clouseau +WORKDIR / +RUN wget https://github.com/cloudant-labs/clouseau/releases/download/2.21.0/clouseau-2.21.0-dist.zip +RUN unzip clouseau-2.21.0-dist.zip +RUN mv clouseau-2.21.0 /opt/clouseau +RUN rm clouseau-2.21.0-dist.zip + +WORKDIR /opt/clouseau +RUN mkdir ./bin +ADD hosting/single/clouseau ./bin/ +ADD hosting/single/log4j.properties . +ADD hosting/single/clouseau.ini . +RUN chmod +x ./bin/clouseau + +# setup CouchDB +WORKDIR /opt/couchdb +ADD hosting/single/vm.args ./etc/ + +# setup minio +WORKDIR /minio +RUN wget https://dl.min.io/server/minio/release/linux-${ARCHITECTURE}64/minio +RUN chmod +x minio + +# setup runner file +WORKDIR / +ADD hosting/single/runner.sh . +RUN chmod +x ./runner.sh + +EXPOSE 10000 +VOLUME /opt/couchdb/data +VOLUME /minio + +# must set this just before running +ENV NODE_ENV=production +CMD ["./runner.sh"] diff --git a/hosting/single/clouseau b/hosting/single/clouseau new file mode 100644 index 0000000000..1095ea24cb --- /dev/null +++ b/hosting/single/clouseau @@ -0,0 +1,12 @@ +#!/bin/sh +/usr/bin/java -server \ + -Xmx2G \ + -Dsun.net.inetaddr.ttl=30 \ + -Dsun.net.inetaddr.negative.ttl=30 \ + -Dlog4j.configuration=file:/opt/clouseau/log4j.properties \ + -XX:OnOutOfMemoryError="kill -9 %p" \ + -XX:+UseConcMarkSweepGC \ + -XX:+CMSParallelRemarkEnabled \ + -classpath '/opt/clouseau/*' \ + com.cloudant.clouseau.Main \ + /opt/clouseau/clouseau.ini \ No newline at end of file diff --git a/hosting/single/clouseau.ini b/hosting/single/clouseau.ini new file mode 100644 index 0000000000..f086cf0398 --- /dev/null +++ b/hosting/single/clouseau.ini @@ -0,0 +1,13 @@ +[clouseau] + +; the name of the Erlang node created by the service, leave this unchanged +name=clouseau@127.0.0.1 + +; set this to the same distributed Erlang cookie used by the CouchDB nodes +cookie=monster + +; the path where you would like to store the search index files +dir=/opt/couchdb/data/search + +; the number of search indexes that can be open simultaneously +max_indexes_open=500 diff --git a/hosting/single/log4j.properties b/hosting/single/log4j.properties new file mode 100644 index 0000000000..9d4d9311bc --- /dev/null +++ b/hosting/single/log4j.properties @@ -0,0 +1,4 @@ +log4j.rootLogger=debug, CONSOLE +log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender +log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout +log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %c [%p] %m%n \ No newline at end of file diff --git a/hosting/single/nginx.conf b/hosting/single/nginx.conf new file mode 100644 index 0000000000..86938ced4e --- /dev/null +++ b/hosting/single/nginx.conf @@ -0,0 +1,116 @@ +user www www; +error_log /etc/nginx/logs/error.log; +pid /etc/nginx/logs/nginx.pid; +worker_processes auto; +worker_rlimit_nofile 8192; + +events { + worker_connections 1024; +} + +http { + limit_req_zone $binary_remote_addr zone=ratelimit:10m rate=20r/s; + proxy_set_header Host $host; + charset utf-8; + sendfile on; + tcp_nopush on; + tcp_nodelay on; + server_tokens off; + types_hash_max_size 2048; + + # buffering + client_header_buffer_size 1k; + client_max_body_size 20M; + ignore_invalid_headers off; + proxy_buffering off; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + map $http_upgrade $connection_upgrade { + default "upgrade"; + } + + server { + listen 10000 default_server; + listen [::]:10000 default_server; + server_name _; + client_max_body_size 1000m; + ignore_invalid_headers off; + proxy_buffering off; + # port_in_redirect off; + + location /app { + proxy_pass http://127.0.0.1:4001; + } + + location = / { + proxy_pass http://127.0.0.1:4001; + } + + location ~ ^/(builder|app_) { + proxy_http_version 1.1; + proxy_set_header Connection $connection_upgrade; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_pass http://127.0.0.1:4001; + } + + location ~ ^/api/(system|admin|global)/ { + proxy_pass http://127.0.0.1:4002; + } + + location /worker/ { + proxy_pass http://127.0.0.1:4002; + rewrite ^/worker/(.*)$ /$1 break; + } + + location /api/ { + # calls to the API are rate limited with bursting + limit_req zone=ratelimit burst=20 nodelay; + + # 120s timeout on API requests + proxy_read_timeout 120s; + proxy_connect_timeout 120s; + proxy_send_timeout 120s; + + proxy_http_version 1.1; + proxy_set_header Connection $connection_upgrade; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + proxy_pass http://127.0.0.1:4001; + } + + location /db/ { + proxy_pass http://127.0.0.1:5984; + rewrite ^/db/(.*)$ /$1 break; + } + + location / { + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_connect_timeout 300; + proxy_http_version 1.1; + proxy_set_header Connection ""; + chunked_transfer_encoding off; + proxy_pass http://127.0.0.1:9000; + } + + client_header_timeout 60; + client_body_timeout 60; + keepalive_timeout 60; + + # gzip + gzip on; + gzip_vary on; + gzip_proxied any; + gzip_comp_level 6; + gzip_types text/plain text/css text/xml application/json application/javascript application/rss+xml application/atom+xml image/svg+xml; + } +} diff --git a/hosting/single/runner.sh b/hosting/single/runner.sh new file mode 100644 index 0000000000..fab8431796 --- /dev/null +++ b/hosting/single/runner.sh @@ -0,0 +1,16 @@ +redis-server --requirepass $REDIS_PASSWORD & +/opt/clouseau/bin/clouseau & +/minio/minio server /minio & +/docker-entrypoint.sh /opt/couchdb/bin/couchdb & +/etc/init.d/nginx restart +pushd app +pm2 start --name app "yarn run:docker" +popd +pushd worker +pm2 start --name worker "yarn run:docker" +popd +sleep 10 +URL=http://${COUCHDB_USER}:${COUCHDB_PASSWORD}@localhost:5984 +curl -X PUT ${URL}/_users +curl -X PUT ${URL}/_replicator +sleep infinity \ No newline at end of file diff --git a/hosting/single/vm.args b/hosting/single/vm.args new file mode 100644 index 0000000000..e9e4416863 --- /dev/null +++ b/hosting/single/vm.args @@ -0,0 +1,32 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. + +# erlang cookie for clouseau security +-name couchdb@127.0.0.1 +-setcookie monster + +# Ensure that the Erlang VM listens on a known port +-kernel inet_dist_listen_min 9100 +-kernel inet_dist_listen_max 9100 + +# Tell kernel and SASL not to log anything +-kernel error_logger silent +-sasl sasl_error_logger false + +# Use kernel poll functionality if supported by emulator ++K true + +# Start a pool of asynchronous IO threads ++A 16 + +# Comment this line out to enable the interactive Erlang shell on startup ++Bd -noinput diff --git a/lerna.json b/lerna.json index 96f102331a..157d6fe849 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "1.0.91-alpha.17", + "version": "1.0.105-alpha.10", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/package.json b/package.json index db60bdd355..ad1b1c4c6f 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,9 @@ "prettier-plugin-svelte": "^2.3.0", "rimraf": "^3.0.2", "rollup-plugin-replace": "^2.2.0", - "svelte": "^3.38.2" + "svelte": "^3.38.2", + "@typescript-eslint/parser": "4.28.0", + "typescript": "4.5.5" }, "scripts": { "setup": "node ./hosting/scripts/setup.js && yarn && yarn bootstrap && yarn build && yarn dev", @@ -41,8 +43,7 @@ "lint": "yarn run lint:eslint && yarn run lint:prettier", "lint:fix:eslint": "eslint --fix packages", "lint:fix:prettier": "prettier --write \"packages/**/*.{js,ts,svelte}\" && prettier --write \"examples/**/*.{js,ts,svelte}\"", - "lint:fix:ts": "lerna run lint:fix", - "lint:fix": "yarn run lint:fix:ts && yarn run lint:fix:prettier && yarn run lint:fix:eslint", + "lint:fix": "yarn run lint:fix:prettier && yarn run lint:fix:eslint", "test:e2e": "lerna run cy:test --stream", "test:e2e:ci": "lerna run cy:ci --stream", "build:specs": "lerna run specs", @@ -55,6 +56,8 @@ "build:docker:develop": "node scripts/pinVersions && lerna run build:docker && npm run build:docker:proxy:compose && cd hosting/scripts/linux/ && ./release-to-docker-hub.sh develop && cd -", "build:docker:airgap": "node hosting/scripts/airgapped/airgappedDockerBuild", "build:digitalocean": "cd hosting/digitalocean && ./build.sh && cd -", + "build:docker:single:image": "docker build -f hosting/single/Dockerfile -t budibase:latest .", + "build:docker:single": "lerna run build && lerna run predocker && npm run build:docker:single:image", "build:docs": "lerna run build:docs", "release:helm": "node scripts/releaseHelmChart", "env:multi:enable": "lerna run env:multi:enable", diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index 64c6d61bda..118ce19dd3 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/backend-core", - "version": "1.0.91-alpha.17", + "version": "1.0.105-alpha.10", "description": "Budibase backend core libraries used in server and worker", "main": "src/index.js", "author": "Budibase", diff --git a/packages/backend-core/src/context/index.js b/packages/backend-core/src/context/index.js index bf815120fa..4f49ebb298 100644 --- a/packages/backend-core/src/context/index.js +++ b/packages/backend-core/src/context/index.js @@ -1,5 +1,6 @@ const env = require("../environment") const { Headers } = require("../../constants") +const { SEPARATOR, DocumentTypes } = require("../db/constants") const cls = require("./FunctionContext") const { getDB } = require("../db") const { getProdAppID, getDevelopmentAppID } = require("../db/conversions") @@ -42,8 +43,39 @@ exports.doInTenant = (tenantId, task) => { }) } +/** + * Given an app ID this will attempt to retrieve the tenant ID from it. + * @return {null|string} The tenant ID found within the app ID. + */ +exports.getTenantIDFromAppID = appId => { + if (!appId) { + return null + } + const split = appId.split(SEPARATOR) + const hasDev = split[1] === DocumentTypes.DEV + if ((hasDev && split.length === 3) || (!hasDev && split.length === 2)) { + return null + } + if (hasDev) { + return split[2] + } else { + return split[1] + } +} + +const setAppTenantId = appId => { + const appTenantId = this.getTenantIDFromAppID(appId) || this.DEFAULT_TENANT_ID + this.updateTenantId(appTenantId) +} + exports.doInAppContext = (appId, task) => { + if (!appId) { + throw new Error("appId is required") + } return cls.run(() => { + // set the app tenant id + setAppTenantId(appId) + // set the app ID cls.setOnContext(ContextKeys.APP_ID, appId) diff --git a/packages/backend-core/src/db/utils.js b/packages/backend-core/src/db/utils.js index e70f3fae79..a44d99643e 100644 --- a/packages/backend-core/src/db/utils.js +++ b/packages/backend-core/src/db/utils.js @@ -9,11 +9,7 @@ const { APP_PREFIX, APP_DEV, } = require("./constants") -const { - getTenantId, - getTenantIDFromAppID, - getGlobalDBName, -} = require("../tenancy") +const { getTenantId, getGlobalDBName } = require("../tenancy") const fetch = require("node-fetch") const { getDB, allDbs } = require("./index") const { getCouchUrl } = require("./pouch") @@ -41,7 +37,6 @@ exports.DocumentTypes = DocumentTypes exports.APP_PREFIX = APP_PREFIX exports.APP_DEV = exports.APP_DEV_PREFIX = APP_DEV exports.SEPARATOR = SEPARATOR -exports.getTenantIDFromAppID = getTenantIDFromAppID exports.isDevApp = isDevApp exports.isProdAppID = isProdAppID exports.isDevAppID = isDevAppID diff --git a/packages/backend-core/src/middleware/appTenancy.js b/packages/backend-core/src/middleware/appTenancy.js deleted file mode 100644 index b0430a0051..0000000000 --- a/packages/backend-core/src/middleware/appTenancy.js +++ /dev/null @@ -1,27 +0,0 @@ -const { - isMultiTenant, - updateTenantId, - isTenantIdSet, - DEFAULT_TENANT_ID, - updateAppId, -} = require("../tenancy") -const ContextFactory = require("../context/FunctionContext") -const { getTenantIDFromAppID } = require("../db/utils") - -module.exports = () => { - return ContextFactory.getMiddleware(ctx => { - // if not in multi-tenancy mode make sure its default and exit - if (!isMultiTenant()) { - updateTenantId(DEFAULT_TENANT_ID) - return - } - // if tenant ID already set no need to continue - if (isTenantIdSet()) { - return - } - const appId = ctx.appId ? ctx.appId : ctx.user ? ctx.user.appId : null - const tenantId = getTenantIDFromAppID(appId) || DEFAULT_TENANT_ID - updateTenantId(tenantId) - updateAppId(appId) - }) -} diff --git a/packages/backend-core/src/middleware/index.js b/packages/backend-core/src/middleware/index.js index 5878479152..6c4c0d8883 100644 --- a/packages/backend-core/src/middleware/index.js +++ b/packages/backend-core/src/middleware/index.js @@ -6,7 +6,6 @@ const { authError } = require("./passport/utils") const authenticated = require("./authenticated") const auditLog = require("./auditLog") const tenancy = require("./tenancy") -const appTenancy = require("./appTenancy") const internalApi = require("./internalApi") const datasourceGoogle = require("./passport/datasource/google") const csrf = require("./csrf") @@ -19,7 +18,6 @@ module.exports = { authenticated, auditLog, tenancy, - appTenancy, authError, internalApi, datasource: { diff --git a/packages/backend-core/src/middleware/passport/datasource/google.js b/packages/backend-core/src/middleware/passport/datasource/google.js index c7553cee50..5046815b1f 100644 --- a/packages/backend-core/src/middleware/passport/datasource/google.js +++ b/packages/backend-core/src/middleware/passport/datasource/google.js @@ -1,15 +1,29 @@ const google = require("../google") -const { Cookies } = require("../../../constants") +const { Cookies, Configs } = require("../../../constants") const { clearCookie, getCookie } = require("../../../utils") const { getDB } = require("../../../db") +const { getScopedConfig } = require("../../../db/utils") const environment = require("../../../environment") +const { getGlobalDB } = require("../../../tenancy") -async function preAuth(passport, ctx, next) { - // get the relevant config - const googleConfig = { +async function fetchGoogleCreds() { + // try and get the config from the tenant + const db = getGlobalDB() + const googleConfig = await getScopedConfig(db, { + type: Configs.GOOGLE, + }) + // or fall back to env variables + const config = googleConfig || { clientID: environment.GOOGLE_CLIENT_ID, clientSecret: environment.GOOGLE_CLIENT_SECRET, } + + return config +} + +async function preAuth(passport, ctx, next) { + // get the relevant config + const googleConfig = await fetchGoogleCreds() let callbackUrl = `${environment.PLATFORM_URL}/api/global/auth/datasource/google/callback` const strategy = await google.strategyFactory(googleConfig, callbackUrl) @@ -26,10 +40,7 @@ async function preAuth(passport, ctx, next) { async function postAuth(passport, ctx, next) { // get the relevant config - const config = { - clientID: environment.GOOGLE_CLIENT_ID, - clientSecret: environment.GOOGLE_CLIENT_SECRET, - } + const config = await fetchGoogleCreds() let callbackUrl = `${environment.PLATFORM_URL}/api/global/auth/datasource/google/callback` const strategy = await google.strategyFactory( diff --git a/packages/backend-core/src/middleware/passport/google.js b/packages/backend-core/src/middleware/passport/google.js index e20239c312..5e95a906d8 100644 --- a/packages/backend-core/src/middleware/passport/google.js +++ b/packages/backend-core/src/middleware/passport/google.js @@ -51,7 +51,10 @@ exports.strategyFactory = async function (config, callbackUrl, saveUserFn) { ) } catch (err) { console.error(err) - throw new Error("Error constructing google authentication strategy", err) + throw new Error( + `Error constructing google authentication strategy: ${err}`, + err + ) } } // expose for testing diff --git a/packages/backend-core/src/security/roles.js b/packages/backend-core/src/security/roles.js index 11abc70bdd..8535cdc716 100644 --- a/packages/backend-core/src/security/roles.js +++ b/packages/backend-core/src/security/roles.js @@ -1,5 +1,5 @@ const { cloneDeep } = require("lodash/fp") -const { BUILTIN_PERMISSION_IDS } = require("./permissions") +const { BUILTIN_PERMISSION_IDS, PermissionLevels } = require("./permissions") const { generateRoleID, getRoleParams, @@ -180,6 +180,20 @@ exports.getUserRoleHierarchy = async (userRoleId, opts = { idOnly: true }) => { return opts.idOnly ? roles.map(role => role._id) : roles } +// this function checks that the provided permissions are in an array format +// some templates/older apps will use a simple string instead of array for roles +// convert the string to an array using the theory that write is higher than read +exports.checkForRoleResourceArray = (rolePerms, resourceId) => { + if (rolePerms && !Array.isArray(rolePerms[resourceId])) { + const permLevel = rolePerms[resourceId] + rolePerms[resourceId] = [permLevel] + if (permLevel === PermissionLevels.WRITE) { + rolePerms[resourceId].push(PermissionLevels.READ) + } + } + return rolePerms +} + /** * Given an app ID this will retrieve all of the roles that are currently within that app. * @return {Promise} An array of the role objects that were found. @@ -209,15 +223,27 @@ exports.getAllRoles = async appId => { roles.push(Object.assign(builtinRole, dbBuiltin)) } } + // check permissions + for (let role of roles) { + if (!role.permissions) { + continue + } + for (let resourceId of Object.keys(role.permissions)) { + role.permissions = exports.checkForRoleResourceArray( + role.permissions, + resourceId + ) + } + } return roles } /** - * This retrieves the required role - * @param permLevel - * @param resourceId - * @param subResourceId - * @return {Promise<{permissions}|Object>} + * This retrieves the required role for a resource + * @param permLevel The level of request + * @param resourceId The resource being requested + * @param subResourceId The sub resource being requested + * @return {Promise<{permissions}|Object>} returns the permissions required to access. */ exports.getRequiredResourceRole = async ( permLevel, diff --git a/packages/backend-core/src/security/sessions.js b/packages/backend-core/src/security/sessions.js index bbe6be299d..1720eeb820 100644 --- a/packages/backend-core/src/security/sessions.js +++ b/packages/backend-core/src/security/sessions.js @@ -14,22 +14,7 @@ function makeSessionID(userId, sessionId) { return `${userId}/${sessionId}` } -exports.createASession = async (userId, session) => { - const client = await redis.getSessionClient() - const sessionId = session.sessionId - if (!session.csrfToken) { - session.csrfToken = uuidv4() - } - session = { - createdAt: new Date().toISOString(), - lastAccessedAt: new Date().toISOString(), - ...session, - userId, - } - await client.store(makeSessionID(userId, sessionId), session, EXPIRY_SECONDS) -} - -exports.invalidateSessions = async (userId, sessionIds = null) => { +async function invalidateSessions(userId, sessionIds = null) { let sessions = [] // If no sessionIds, get all the sessions for the user @@ -55,6 +40,24 @@ exports.invalidateSessions = async (userId, sessionIds = null) => { await Promise.all(promises) } +exports.createASession = async (userId, session) => { + // invalidate all other sessions + await invalidateSessions(userId) + + const client = await redis.getSessionClient() + const sessionId = session.sessionId + if (!session.csrfToken) { + session.csrfToken = uuidv4() + } + session = { + createdAt: new Date().toISOString(), + lastAccessedAt: new Date().toISOString(), + ...session, + userId, + } + await client.store(makeSessionID(userId, sessionId), session, EXPIRY_SECONDS) +} + exports.updateSessionTTL = async session => { const client = await redis.getSessionClient() const key = makeSessionID(session.userId, session.sessionId) @@ -67,8 +70,6 @@ exports.endSession = async (userId, sessionId) => { await client.delete(makeSessionID(userId, sessionId)) } -exports.getUserSessions = getSessionsForUser - exports.getSession = async (userId, sessionId) => { try { const client = await redis.getSessionClient() @@ -84,3 +85,6 @@ exports.getAllSessions = async () => { const sessions = await client.scan() return sessions.map(session => session.value) } + +exports.getUserSessions = getSessionsForUser +exports.invalidateSessions = invalidateSessions diff --git a/packages/backend-core/src/tenancy/tenancy.js b/packages/backend-core/src/tenancy/tenancy.js index 8360198b60..24acc16862 100644 --- a/packages/backend-core/src/tenancy/tenancy.js +++ b/packages/backend-core/src/tenancy/tenancy.js @@ -1,6 +1,11 @@ const { getDB } = require("../db") -const { SEPARATOR, StaticDatabases, DocumentTypes } = require("../db/constants") -const { getTenantId, DEFAULT_TENANT_ID, isMultiTenant } = require("../context") +const { SEPARATOR, StaticDatabases } = require("../db/constants") +const { + getTenantId, + DEFAULT_TENANT_ID, + isMultiTenant, + getTenantIDFromAppID, +} = require("../context") const env = require("../environment") const TENANT_DOC = StaticDatabases.PLATFORM_INFO.docs.tenants @@ -118,26 +123,6 @@ exports.getTenantUser = async identifier => { } } -/** - * Given an app ID this will attempt to retrieve the tenant ID from it. - * @return {null|string} The tenant ID found within the app ID. - */ -exports.getTenantIDFromAppID = appId => { - if (!appId) { - return null - } - const split = appId.split(SEPARATOR) - const hasDev = split[1] === DocumentTypes.DEV - if ((hasDev && split.length === 3) || (!hasDev && split.length === 2)) { - return null - } - if (hasDev) { - return split[2] - } else { - return split[1] - } -} - exports.isUserInAppTenant = (appId, user = null) => { let userTenantId if (user) { @@ -145,7 +130,7 @@ exports.isUserInAppTenant = (appId, user = null) => { } else { userTenantId = getTenantId() } - const tenantId = exports.getTenantIDFromAppID(appId) || DEFAULT_TENANT_ID + const tenantId = getTenantIDFromAppID(appId) || DEFAULT_TENANT_ID return tenantId === userTenantId } diff --git a/packages/backend-core/src/utils.js b/packages/backend-core/src/utils.js index 7d085d24c9..0118b36f52 100644 --- a/packages/backend-core/src/utils.js +++ b/packages/backend-core/src/utils.js @@ -1,4 +1,9 @@ -const { DocumentTypes, SEPARATOR, ViewNames } = require("./db/utils") +const { + DocumentTypes, + SEPARATOR, + ViewNames, + getAllApps, +} = require("./db/utils") const jwt = require("jsonwebtoken") const { options } = require("./middleware/passport/jwt") const { queryGlobalView } = require("./db/views") @@ -7,8 +12,10 @@ const env = require("./environment") const userCache = require("./cache/user") const { getUserSessions, invalidateSessions } = require("./security/sessions") const events = require("./events") +const tenancy = require("./tenancy") const APP_PREFIX = DocumentTypes.APP + SEPARATOR +const PROD_APP_PREFIX = "/app/" function confirmAppId(possibleAppId) { return possibleAppId && possibleAppId.startsWith(APP_PREFIX) @@ -16,16 +23,35 @@ function confirmAppId(possibleAppId) { : undefined } +async function resolveAppUrl(ctx) { + const appUrl = ctx.path.split("/")[2] + let possibleAppUrl = `/${appUrl.toLowerCase()}` + + let tenantId = tenancy.getTenantId() + if (!env.SELF_HOSTED && ctx.subdomains.length) { + // always use the tenant id from the url in cloud + tenantId = ctx.subdomains[0] + } + + // search prod apps for a url that matches + const apps = await tenancy.doInTenant(tenantId, () => + getAllApps({ dev: false }) + ) + const app = apps.filter( + a => a.url && a.url.toLowerCase() === possibleAppUrl + )[0] + + return app && app.appId ? app.appId : undefined +} + /** * Given a request tries to find the appId, which can be located in various places * @param {object} ctx The main request body to look through. * @returns {string|undefined} If an appId was found it will be returned. */ -exports.getAppId = ctx => { - const options = [ctx.headers[Headers.APP_ID], ctx.params.appId] - if (ctx.subdomains) { - options.push(ctx.subdomains[1]) - } +exports.getAppIdFromCtx = async ctx => { + // look in headers + const options = [ctx.headers[Headers.APP_ID]] let appId for (let option of options) { appId = confirmAppId(option) @@ -34,16 +60,24 @@ exports.getAppId = ctx => { } } - // look in body if can't find it in subdomain + // look in body if (!appId && ctx.request.body && ctx.request.body.appId) { appId = confirmAppId(ctx.request.body.appId) } + + // look in the url - dev app let appPath = ctx.request.headers.referrer || ctx.path.split("/").filter(subPath => subPath.startsWith(APP_PREFIX)) - if (!appId && appPath.length !== 0) { + if (!appId && appPath.length) { appId = confirmAppId(appPath[0]) } + + // look in the url - prod app + if (!appId && ctx.path.startsWith(PROD_APP_PREFIX)) { + appId = confirmAppId(await resolveAppUrl(ctx)) + } + return appId } diff --git a/packages/backend-core/yarn.lock b/packages/backend-core/yarn.lock index 2e06376084..7c1f7114bd 100644 --- a/packages/backend-core/yarn.lock +++ b/packages/backend-core/yarn.lock @@ -3619,9 +3619,9 @@ mimic-fn@^2.1.0: brace-expansion "^1.1.7" minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== mixin-deep@^1.2.0: version "1.3.2" diff --git a/packages/bbui/package.json b/packages/bbui/package.json index 26a2bce621..d037ca9a86 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "1.0.91-alpha.17", + "version": "1.0.105-alpha.10", "license": "MPL-2.0", "svelte": "src/index.js", "module": "dist/bbui.es.js", @@ -38,7 +38,7 @@ ], "dependencies": { "@adobe/spectrum-css-workflow-icons": "^1.2.1", - "@budibase/string-templates": "^1.0.91-alpha.17", + "@budibase/string-templates": "^1.0.105-alpha.10", "@spectrum-css/actionbutton": "^1.0.1", "@spectrum-css/actiongroup": "^1.0.1", "@spectrum-css/avatar": "^3.0.2", diff --git a/packages/bbui/src/Button/Button.svelte b/packages/bbui/src/Button/Button.svelte index a3d2df069a..e8f6b4500e 100644 --- a/packages/bbui/src/Button/Button.svelte +++ b/packages/bbui/src/Button/Button.svelte @@ -13,6 +13,7 @@ export let icon = undefined export let active = false export let tooltip = undefined + export let dataCy let showTooltip = false @@ -27,6 +28,7 @@ class:active class="spectrum-Button spectrum-Button--size{size.toUpperCase()}" {disabled} + data-cy={dataCy} on:click|preventDefault on:mouseover={() => (showTooltip = true)} on:focus={() => (showTooltip = true)} diff --git a/packages/bbui/src/Form/Core/DatePicker.svelte b/packages/bbui/src/Form/Core/DatePicker.svelte index c1c4cc866f..fd67fa41bb 100644 --- a/packages/bbui/src/Form/Core/DatePicker.svelte +++ b/packages/bbui/src/Form/Core/DatePicker.svelte @@ -19,18 +19,33 @@ const dispatch = createEventDispatcher() const flatpickrId = `${uuid()}-wrapper` let open = false - let flatpickr, flatpickrOptions, isTimeOnly + let flatpickr, flatpickrOptions + + const resolveTimeStamp = timestamp => { + let maskedDate = new Date(`0-${timestamp}`) + + if (maskedDate instanceof Date && !isNaN(maskedDate.getTime())) { + return maskedDate + } else { + return null + } + } - $: isTimeOnly = !timeOnly && value ? !isNaN(new Date(`0-${value}`)) : timeOnly $: flatpickrOptions = { element: `#${flatpickrId}`, - enableTime: isTimeOnly || enableTime || false, - noCalendar: isTimeOnly || false, + enableTime: timeOnly || enableTime || false, + noCalendar: timeOnly || false, altInput: true, - altFormat: isTimeOnly ? "H:i" : enableTime ? "F j Y, H:i" : "F j, Y", + altFormat: timeOnly ? "H:i" : enableTime ? "F j Y, H:i" : "F j, Y", wrap: true, appendTo, disableMobile: "true", + onReady: () => { + let timestamp = resolveTimeStamp(value) + if (timeOnly && timestamp) { + dispatch("change", timestamp.toISOString()) + } + }, } const handleChange = event => { @@ -39,10 +54,9 @@ if (newValue) { newValue = newValue.toISOString() } - // if time only set date component to today + // if time only set date component to 2000-01-01 if (timeOnly) { - const todayDate = new Date().toISOString().split("T")[0] - newValue = `${todayDate}T${newValue.split("T")[1]}` + newValue = `2000-01-01T${newValue.split("T")[1]}` } dispatch("change", newValue) } @@ -76,10 +90,13 @@ return null } let date - let time = new Date(`0-${val}`) + let time + // it is a string like 00:00:00, just time - if (timeOnly || (typeof val === "string" && !isNaN(time))) { - date = time + let ts = resolveTimeStamp(val) + + if (timeOnly && ts) { + date = ts } else if (val instanceof Date) { // Use real date obj if already parsed date = val @@ -101,7 +118,7 @@ } -{#key isTimeOnly} +{#key timeOnly} {cancelText} {/if} {#if showConfirmButton} - + + + {/if} {/if} @@ -169,4 +177,8 @@ .spectrum-Dialog-buttonGroup { padding-left: 0; } + + .confirm-wrap :global(.spectrum-Button-label) { + display: contents; + } diff --git a/packages/bbui/yarn.lock b/packages/bbui/yarn.lock index 5baad30282..0bff3e86d9 100644 --- a/packages/bbui/yarn.lock +++ b/packages/bbui/yarn.lock @@ -1574,9 +1574,9 @@ minimatch@^3.0.4: brace-expansion "^1.1.7" minimist@^1.2.0, minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== mkdirp@~0.5.1: version "0.5.5" diff --git a/packages/builder/cypress/integration/changeAppIconAndColour.spec.js b/packages/builder/cypress/integration/changeAppIconAndColour.spec.js index 92d03a102d..0db2d49e3f 100644 --- a/packages/builder/cypress/integration/changeAppIconAndColour.spec.js +++ b/packages/builder/cypress/integration/changeAppIconAndColour.spec.js @@ -5,10 +5,10 @@ filterTests(['all'], () => { before(() => { cy.login() }) - + it("should change the icon and colour for an application", () => { // Search for test application - cy.searchForApplication("Cypress Tests") + cy.applicationInAppTable("Cypress Tests") cy.get(".appTable") .within(() => { cy.get(".spectrum-Icon").eq(1).click() diff --git a/packages/builder/cypress/integration/createApp.spec.js b/packages/builder/cypress/integration/createApp.spec.js index 273683aec8..4867534241 100644 --- a/packages/builder/cypress/integration/createApp.spec.js +++ b/packages/builder/cypress/integration/createApp.spec.js @@ -2,11 +2,164 @@ import filterTests from '../support/filterTests' filterTests(['smoke', 'all'], () => { context("Create an Application", () => { - it("should create a new application", () => { + + before(() => { cy.login() - cy.createTestApp() - cy.visit(`${Cypress.config().baseUrl}/builder`) - cy.contains("Cypress Tests").should("exist") + cy.deleteApp("Cypress Tests") }) + + if (!(Cypress.env("TEST_ENV"))) { + it("should show the new user UI/UX", () => { + cy.visit(`${Cypress.config().baseUrl}/builder`) + cy.get(`[data-cy="create-app-btn"]`).contains('Start from scratch').should("exist") + cy.get(`[data-cy="import-app-btn"]`).should("exist") + + cy.get(".template-category-filters").should("exist") + cy.get(".template-categories").should("exist") + + cy.get(".appTable").should("not.exist") + }) + } + + it("should provide filterable templates", () => { + cy.visit(`${Cypress.config().baseUrl}/builder`) + cy.wait(500) + + if (Cypress.env("TEST_ENV")) { + cy.get(".spectrum-Button").contains("Templates").click({force: true}) + } + + cy.get(".template-category-filters").should("exist") + cy.get(".template-categories").should("exist") + + cy.get(".template-category").its('length').should('be.gt', 1) + cy.get(".template-category-filters .spectrum-ActionButton").its('length').should('be.gt', 2) + + cy.get(".template-category-filters .spectrum-ActionButton").eq(1).click() + cy.get(".template-category").should('have.length', 1) + + cy.get(".template-category-filters .spectrum-ActionButton").eq(0).click() + cy.get(".template-category").its('length').should('be.gt', 1) + }) + + it("should enforce a valid url before submission", () => { + cy.visit(`${Cypress.config().baseUrl}/builder`) + cy.wait(500) + + // Start create app process. If apps already exist, click second button + cy.get(`[data-cy="create-app-btn"]`).click({ force: true }) + cy.request(`${Cypress.config().baseUrl}/api/applications?status=all`) + .its("body") + .then(val => { + if (val.length > 0) { + cy.get(`[data-cy="create-app-btn"]`).click({ force: true }) + } + }) + + const appName = "Cypress Tests" + cy.get(".spectrum-Modal").within(() => { + + //Auto fill + cy.get("input").eq(0).type(appName).should("have.value", appName).blur() + cy.get("input").eq(1).should("have.value", "/cypress-tests") + cy.get(".spectrum-ButtonGroup").contains("Create app").should('not.be.disabled') + + //Empty the app url - disabled create + cy.get("input").eq(1).clear().blur() + cy.get(".spectrum-ButtonGroup").contains("Create app").should('be.disabled') + + //Invalid url + cy.get("input").eq(1).type("/new app-url").blur() + cy.get(".spectrum-ButtonGroup").contains("Create app").should('be.disabled') + + //Specifically alter the url + cy.get("input").eq(1).clear() + cy.get("input").eq(1).type("another-app-name").blur() + cy.get("input").eq(1).should("have.value", "/another-app-name") + cy.get("input").eq(0).should("have.value", appName) + cy.get(".spectrum-ButtonGroup").contains("Create app").should('not.be.disabled') + + }) + }) + + it("should create the first application from scratch", () => { + const appName = "Cypress Tests" + cy.createApp(appName) + + cy.visit(`${Cypress.config().baseUrl}/builder`) + cy.wait(1000) + + cy.applicationInAppTable(appName) + cy.deleteApp(appName) + }) + + it("should generate the first application from a template", () => { + cy.visit(`${Cypress.config().baseUrl}/builder`) + cy.wait(500) + + // Navigate to Create new app section if apps already exist + cy.request(`${Cypress.config().baseUrl}/api/applications?status=all`) + .its("body") + .then(val => { + if (val.length > 0) { + cy.get(`[data-cy="create-app-btn"]`).click({ force: true }) + } + }) + + cy.get(".template-category-filters").should("exist") + cy.get(".template-categories").should("exist") + + // Select template + cy.get('.template-category').eq(0).within(() => { + const card = cy.get('.template-card').eq(0).should("exist"); + const cardOverlay = card.get('.template-thumbnail-action-overlay').should("exist") + cardOverlay.invoke("show") + cardOverlay.get("button").contains("Use template").should("exist").click({force: true}) + }) + + // CMD Create app from theme card + cy.get(".spectrum-Modal").should('be.visible') + + const templateName = cy.get(".spectrum-Modal .template-thumbnail-text") + templateName.invoke('text') + .then(templateNameText => { + const templateNameParsed = "/"+templateNameText.toLowerCase().replace(/\s+/g, "-") + cy.get(".spectrum-Modal input").eq(0).should("have.value", templateNameText) + cy.get(".spectrum-Modal input").eq(1).should("have.value", templateNameParsed) + + cy.get(".spectrum-Modal .spectrum-ButtonGroup").contains("Create app").click() + cy.wait(5000) + + cy.visit(`${Cypress.config().baseUrl}/builder`) + cy.wait(1000) + + cy.applicationInAppTable(templateNameText) + cy.deleteApp(templateNameText) + }); + + }) + + it("should display a second application and app filtering", () => { + // Create first app + const appName = "Cypress Tests" + cy.createApp(appName) + + cy.visit(`${Cypress.config().baseUrl}/builder`) + cy.wait(500) + + // Create second app + const secondAppName = "Second App Demo" + cy.createApp(secondAppName) + + cy.visit(`${Cypress.config().baseUrl}/builder`) + cy.wait(500) + + //Both applications should exist and be searchable + cy.searchForApplication(appName) + cy.searchForApplication(secondAppName) + + cy.deleteApp(secondAppName) + }) + }) }) diff --git a/packages/builder/cypress/integration/createUserAndRoles.spec.js b/packages/builder/cypress/integration/createUserAndRoles.spec.js index ce6d370187..5cd3697e38 100644 --- a/packages/builder/cypress/integration/createUserAndRoles.spec.js +++ b/packages/builder/cypress/integration/createUserAndRoles.spec.js @@ -7,6 +7,8 @@ filterTests(["smoke", "all"], () => { }) it("should create a user", () => { + cy.visit(`${Cypress.config().baseUrl}/builder`) + cy.wait(1000) cy.createUser("bbuser@test.com") cy.get(".spectrum-Table").should("contain", "bbuser") }) @@ -21,95 +23,104 @@ filterTests(["smoke", "all"], () => { cy.get(".spectrum-Table").eq(0).contains("No rows found") }) - it("should assign role types", () => { - // 3 apps minimum required - to assign an app to each role type - cy.request(`${Cypress.config().baseUrl}/api/applications?status=all`) - .its("body") - .then(val => { - if (val.length < 3) { - for (let i = 1; i < 3; i++) { - const uuid = () => Cypress._.random(0, 1e6) - const name = uuid() - cy.createApp(name) + if (Cypress.env("TEST_ENV")) { + it("should assign role types", () => { + // 3 apps minimum required - to assign an app to each role type + cy.request(`${Cypress.config().baseUrl}/api/applications?status=all`) + .its("body") + .then(val => { + if (val.length < 3) { + for (let i = 1; i < 3; i++) { + const uuid = () => Cypress._.random(0, 1e6) + const name = uuid() + if(i < 1){ + cy.createApp(name) + } else { + cy.visit(`${Cypress.config().baseUrl}/builder`) + cy.wait(500) + cy.get(`[data-cy="create-app-btn"]`).click({ force: true }) + cy.createAppFromScratch(name) + } + } } - } - }) - // Navigate back to the user - cy.visit(`${Cypress.config().baseUrl}/builder`) - cy.wait(500) - cy.get(".spectrum-SideNav").contains("Users").click() - cy.wait(500) - cy.get(".spectrum-Table").contains("bbuser").click() - cy.wait(1000) - for (let i = 0; i < 3; i++) { - cy.get(".spectrum-Table") - .eq(1) - .find(".spectrum-Table-row") - .eq(0) - .find(".spectrum-Table-cell") - .eq(0) - .click() - cy.wait(500) - cy.get(".spectrum-Dialog-grid") - .contains("Choose an option") - .click() - .then(() => { - cy.wait(1000) - if (i == 0) { - cy.get(".spectrum-Popover").contains("Admin").click() - } - if (i == 1) { - cy.get(".spectrum-Popover").contains("Power").click() - } - if (i == 2) { - cy.get(".spectrum-Popover").contains("Basic").click() - } - cy.wait(1000) - cy.get(".spectrum-Button") - .contains("Update role") - .click({ force: true }) }) - } - // Confirm roles exist within Configure roles table - cy.wait(2000) - cy.get(".spectrum-Table") - .eq(0) - .within(assginedRoles => { - expect(assginedRoles).to.contain("Admin") - expect(assginedRoles).to.contain("Power") - expect(assginedRoles).to.contain("Basic") - }) - }) - - it("should unassign role types", () => { - // Set each app within Configure roles table to 'No Access' - cy.get(".spectrum-Table") - .eq(0) - .find(".spectrum-Table-row") - .its("length") - .then(len => { - for (let i = 0; i < len; i++) { - cy.get(".spectrum-Table") - .eq(0) - .find(".spectrum-Table-row") - .eq(0) - .find(".spectrum-Table-cell") - .eq(0) - .click() - .then(() => { - cy.get(".spectrum-Picker").eq(1).click({ force: true }) - cy.wait(500) - cy.get(".spectrum-Popover").contains("No Access").click() - }) - cy.get(".spectrum-Button") - .contains("Update role") - .click({ force: true }) - cy.wait(1000) - } - }) - // Confirm Configure roles table no longer has any apps in it - cy.get(".spectrum-Table").eq(0).contains("No rows found") - }) + // Navigate back to the user + cy.visit(`${Cypress.config().baseUrl}/builder`) + cy.wait(500) + cy.get(".spectrum-SideNav").contains("Users").click() + cy.wait(500) + cy.get(".spectrum-Table").contains("bbuser").click() + cy.wait(1000) + for (let i = 0; i < 3; i++) { + cy.get(".spectrum-Table") + .eq(1) + .find(".spectrum-Table-row") + .eq(0) + .find(".spectrum-Table-cell") + .eq(0) + .click() + cy.wait(500) + cy.get(".spectrum-Dialog-grid") + .contains("Choose an option") + .click() + .then(() => { + cy.wait(1000) + if (i == 0) { + cy.get(".spectrum-Popover").contains("Admin").click() + } + if (i == 1) { + cy.get(".spectrum-Popover").contains("Power").click() + } + if (i == 2) { + cy.get(".spectrum-Popover").contains("Basic").click() + } + cy.wait(1000) + cy.get(".spectrum-Button") + .contains("Update role") + .click({ force: true }) + }) + } + // Confirm roles exist within Configure roles table + cy.wait(2000) + cy.get(".spectrum-Table") + .eq(0) + .within(assginedRoles => { + expect(assginedRoles).to.contain("Admin") + expect(assginedRoles).to.contain("Power") + expect(assginedRoles).to.contain("Basic") + }) + }) + + it("should unassign role types", () => { + // Set each app within Configure roles table to 'No Access' + cy.get(".spectrum-Table") + .eq(0) + .find(".spectrum-Table-row") + .its("length") + .then(len => { + for (let i = 0; i < len; i++) { + cy.get(".spectrum-Table") + .eq(0) + .find(".spectrum-Table-row") + .eq(0) + .find(".spectrum-Table-cell") + .eq(0) + .click() + .then(() => { + cy.get(".spectrum-Picker").eq(1).click({ force: true }) + cy.wait(500) + cy.get(".spectrum-Popover").contains("No Access").click() + }) + cy.get(".spectrum-Button") + .contains("Update role") + .click({ force: true }) + cy.wait(1000) + } + }) + // Confirm Configure roles table no longer has any apps in it + cy.get(".spectrum-Table").eq(0).contains("No rows found") + }) + } it("should enable Developer access", () => { // Enable Developer access diff --git a/packages/builder/cypress/integration/createView.spec.js b/packages/builder/cypress/integration/createView.spec.js index 6b06cde0bc..a8c3b03cee 100644 --- a/packages/builder/cypress/integration/createView.spec.js +++ b/packages/builder/cypress/integration/createView.spec.js @@ -4,6 +4,7 @@ filterTests(['smoke', 'all'], () => { context("Create a View", () => { before(() => { cy.login() + cy.createTestApp() cy.createTable("data") cy.addColumn("data", "group", "Text") diff --git a/packages/builder/cypress/integration/queryLevelTransformers.spec.js b/packages/builder/cypress/integration/queryLevelTransformers.spec.js index e96a6dba29..bec0825e70 100644 --- a/packages/builder/cypress/integration/queryLevelTransformers.spec.js +++ b/packages/builder/cypress/integration/queryLevelTransformers.spec.js @@ -4,8 +4,7 @@ filterTests(["smoke", "all"], () => { context("Query Level Transformers", () => { before(() => { cy.login() - cy.deleteApp("Cypress Tests") - cy.createApp("Cypress Tests") + cy.createTestApp() }) it("should write a transformer function", () => { diff --git a/packages/builder/cypress/integration/renameAnApplication.spec.js b/packages/builder/cypress/integration/renameAnApplication.spec.js index 48e829fa03..f4899f98a0 100644 --- a/packages/builder/cypress/integration/renameAnApplication.spec.js +++ b/packages/builder/cypress/integration/renameAnApplication.spec.js @@ -1,133 +1,128 @@ import filterTests from "../support/filterTests" filterTests(['all'], () => { - context("Rename an App", () => { - beforeEach(() => { - cy.login() - cy.createTestApp() - }) + context("Rename an App", () => { + beforeEach(() => { + cy.login() + cy.createTestApp() + }) it("should rename an unpublished application", () => { - const appName = "Cypress Tests" - const appRename = "Cypress Renamed" - // Rename app, Search for app, Confirm name was changed - cy.get(".home-logo").click() - renameApp(appName, appRename) - cy.reload() - cy.wait(1000) - cy.searchForApplication(appRename) - cy.get(".appTable").find(".title").should("have.length", 1) - // Set app name back to Cypress Tests - cy.reload() - cy.wait(1000) - renameApp(appRename, appName) + const appName = "Cypress Tests" + const appRename = "Cypress Renamed" + // Rename app, Search for app, Confirm name was changed + cy.visit(`${Cypress.config().baseUrl}/builder`) + cy.wait(500) + renameApp(appName, appRename) + cy.reload() + cy.wait(1000) + cy.searchForApplication(appRename) + cy.get(".appTable").find(".title").should("have.length", 1) + cy.applicationInAppTable(appRename) + // Set app name back to Cypress Tests + cy.reload() + cy.wait(1000) + renameApp(appRename, appName) }) - + xit("Should rename a published application", () => { - // It is not possible to rename a published application - const appName = "Cypress Tests" - const appRename = "Cypress Renamed" - // Publish the app - cy.get(".toprightnav") - cy.get(".spectrum-Button").contains("Publish").click({force: true}) - cy.get(".spectrum-Dialog-grid") - .within(() => { - // Click publish again within the modal - cy.get(".spectrum-Button").contains("Publish").click({force: true}) - }) - // Rename app, Search for app, Confirm name was changed - cy.get(".home-logo").click() - renameApp(appName, appRename, true) - cy.searchForApplication(appRename) - cy.get(".appTable").find(".wrapper").should("have.length", 1) + // It is not possible to rename a published application + const appName = "Cypress Tests" + const appRename = "Cypress Renamed" + // Publish the app + cy.get(".toprightnav") + cy.get(".spectrum-Button").contains("Publish").click({ force: true }) + cy.get(".spectrum-Dialog-grid") + .within(() => { + // Click publish again within the modal + cy.get(".spectrum-Button").contains("Publish").click({ force: true }) + }) + // Rename app, Search for app, Confirm name was changed + cy.visit(`${Cypress.config().baseUrl}/builder`) + cy.wait(500) + renameApp(appName, appRename, true) + cy.get(".appTable").find(".wrapper").should("have.length", 1) + cy.applicationInAppTable(appRename) }) it("Should try to rename an application to have no name", () => { - const appName = "Cypress Tests" - cy.get(".home-logo").click() - renameApp(appName, " ", false, true) - cy.wait(500) - // Close modal and confirm name has not been changed - cy.get(".spectrum-Dialog-grid").contains("Cancel").click() - cy.reload() - cy.wait(1000) - cy.searchForApplication(appName) - cy.get(".appTable").find(".title").should("have.length", 1) - + const appName = "Cypress Tests" + cy.visit(`${Cypress.config().baseUrl}/builder`) + cy.wait(500) + renameApp(appName, " ", false, true) + cy.wait(500) + // Close modal and confirm name has not been changed + cy.get(".spectrum-Dialog-grid").contains("Cancel").click() + cy.reload() + cy.wait(1000) + cy.applicationInAppTable(appName) }) xit("Should create two applications with the same name", () => { - // It is not possible to have applications with the same name - const appName = "Cypress Tests" - cy.visit(`${Cypress.config().baseUrl}/builder`) - cy.wait(500) - cy.get(".spectrum-Button").contains("Create app").click({force: true}) - cy.contains(/Start from scratch/).click() - cy.get(".spectrum-Modal") + // It is not possible to have applications with the same name + const appName = "Cypress Tests" + cy.visit(`${Cypress.config().baseUrl}/builder`) + cy.wait(500) + cy.get(".spectrum-Button").contains("Create app").click({ force: true }) + cy.contains(/Start from scratch/).click() + cy.get(".spectrum-Modal") .within(() => { - cy.get("input").eq(0).type(appName) - cy.get(".spectrum-ButtonGroup").contains("Create app").click({force: true}) - cy.get(".error").should("have.text", "Another app with the same name already exists") + cy.get("input").eq(0).type(appName) + cy.get(".spectrum-ButtonGroup").contains("Create app").click({ force: true }) + cy.get(".error").should("have.text", "Another app with the same name already exists") }) }) it("should validate application names", () => { - // App name must be letters, numbers and spaces only - // This test checks numbers and special characters specifically - const appName = "Cypress Tests" - const numberName = 12345 - const specialCharName = "£$%^" - cy.get(".home-logo").click() - renameApp(appName, numberName) - cy.reload() - cy.wait(1000) - cy.searchForApplication(numberName) - cy.get(".appTable").find(".title").should("have.length", 1) - cy.reload() - cy.wait(1000) - renameApp(numberName, specialCharName) - cy.get(".error").should("have.text", "App name must be letters, numbers and spaces only") - // Set app name back to Cypress Tests - cy.reload() - cy.wait(1000) - renameApp(numberName, appName) + // App name must be letters, numbers and spaces only + // This test checks numbers and special characters specifically + const appName = "Cypress Tests" + const numberName = 12345 + const specialCharName = "£$%^" + cy.visit(`${Cypress.config().baseUrl}/builder`) + cy.wait(500) + renameApp(appName, numberName) + cy.reload() + cy.wait(1000) + cy.applicationInAppTable(numberName) + cy.reload() + cy.wait(1000) + renameApp(numberName, specialCharName) + cy.get(".error").should("have.text", "App name must be letters, numbers and spaces only") + // Set app name back to Cypress Tests + cy.reload() + cy.wait(1000) + renameApp(numberName, appName) }) - - const renameApp = (originalName, changedName, published, noName) => { - cy.searchForApplication(originalName) - cy.request(`${Cypress.config().baseUrl}/api/applications?status=all`) - .its("body") - .then(val => { - if (val.length > 0) { - cy.get(".appTable") - .within(() => { - cy.get(".spectrum-Icon").eq(1).click() - }) - // Check for when an app is published - if (published == true){ - // Should not have Edit as option, will unpublish app - cy.should("not.have.value", "Edit") - cy.get(".spectrum-Menu").contains("Unpublish").click() - cy.get(".spectrum-Dialog-grid").contains("Unpublish app").click() - cy.get(".appTable > :nth-child(5) > :nth-child(2) > .spectrum-Icon").click() - } - cy.contains("Edit").click() - cy.get(".spectrum-Modal") - .within(() => { - if (noName == true){ - cy.get("input").clear() - cy.get(".spectrum-Dialog-grid").click() - .contains("App name must be letters, numbers and spaces only") - return cy - } - cy.get("input").clear() - cy.get("input").eq(0).type(changedName).should("have.value", changedName).blur() - cy.get(".spectrum-ButtonGroup").contains("Save").click({force: true}) - cy.wait(500) - }) - } - }) - } + const renameApp = (originalName, changedName, published, noName) => { + cy.searchForApplication(originalName) + cy.get(".appTable") + .within(() => { + cy.get(".spectrum-Icon").eq(1).click() + }) + // Check for when an app is published + if (published == true) { + // Should not have Edit as option, will unpublish app + cy.should("not.have.value", "Edit") + cy.get(".spectrum-Menu").contains("Unpublish").click() + cy.get(".spectrum-Dialog-grid").contains("Unpublish app").click() + cy.get(".appTable > :nth-child(5) > :nth-child(2) > .spectrum-Icon").click() + } + cy.contains("Edit").click() + cy.get(".spectrum-Modal") + .within(() => { + if (noName == true) { + cy.get("input").clear() + cy.get(".spectrum-Dialog-grid").click() + .contains("App name must be letters, numbers and spaces only") + return cy + } + cy.get("input").clear() + cy.get("input").eq(0).type(changedName).should("have.value", changedName).blur() + cy.get(".spectrum-ButtonGroup").contains("Save").click({ force: true }) + cy.wait(500) + }) + } }) }) diff --git a/packages/builder/cypress/support/commands.js b/packages/builder/cypress/support/commands.js index 699cf1fbf0..f4ccdcca24 100644 --- a/packages/builder/cypress/support/commands.js +++ b/packages/builder/cypress/support/commands.js @@ -35,7 +35,17 @@ Cypress.Commands.add("login", () => { Cypress.Commands.add("createApp", name => { cy.visit(`${Cypress.config().baseUrl}/builder`) cy.wait(500) - cy.get(".spectrum-Button").contains("Create app").click({ force: true }) + cy.get(`[data-cy="create-app-btn"]`).click({ force: true }) + + // If apps already exist + cy.request(`${Cypress.config().baseUrl}/api/applications?status=all`) + .its("body") + .then(val => { + if (val.length > 0) { + cy.get(`[data-cy="create-app-btn"]`).click({ force: true }) + } + }) + cy.get(".spectrum-Modal").within(() => { cy.get("input").eq(0).type(name).should("have.value", name).blur() cy.get(".spectrum-ButtonGroup").contains("Create app").click() @@ -51,10 +61,30 @@ Cypress.Commands.add("deleteApp", name => { .its("body") .then(val => { if (val.length > 0) { - cy.searchForApplication(name) - cy.get(".appTable").within(() => { - cy.get(".spectrum-Icon").eq(1).click() - }) + if (Cypress.env("TEST_ENV")) { + cy.searchForApplication(name) + cy.get(".appTable").within(() => { + cy.get(".spectrum-Icon").eq(1).click() + }) + } else { + const appId = val.reduce((acc, app) => { + if (name === app.name) { + acc = app.appId + } + return acc + }, "") + + if (appId == "") { + return + } + + const appIdParsed = appId.split("_").pop() + const actionEleId = `[data-cy=row_actions_${appIdParsed}]` + cy.get(actionEleId).within(() => { + cy.get(".spectrum-Icon").eq(0).click() + }) + } + cy.get(".spectrum-Menu").then($menu => { if ($menu.text().includes("Unpublish")) { cy.get(".spectrum-Menu").contains("Unpublish").click() @@ -80,22 +110,18 @@ Cypress.Commands.add("deleteAllApps", () => { .its("body") .then(val => { for (let i = 0; i < val.length; i++) { - cy.get(".spectrum-Heading") - .eq(1) - .then(app => { - const name = app.text() - cy.get(".title") - .children() - .within(() => { - cy.get(".spectrum-Icon").eq(0).click() - }) - cy.get(".spectrum-Menu").contains("Delete").click() - cy.get(".spectrum-Dialog-grid").within(() => { - cy.get("input").type(name) - cy.get(".spectrum-Button--warning").click() - }) - cy.reload() - }) + const appIdParsed = val[i].appId.split("_").pop() + const actionEleId = `[data-cy=row_actions_${appIdParsed}]` + cy.get(actionEleId).within(() => { + cy.get(".spectrum-Icon").eq(0).click() + }) + + cy.get(".spectrum-Menu").contains("Delete").click() + cy.get(".spectrum-Dialog-grid").within(() => { + cy.get("input").type(val[i].name) + cy.get(".spectrum-Button--warning").click() + }) + cy.reload() } }) }) @@ -190,9 +216,11 @@ Cypress.Commands.add("addRowMultiValue", values => { Cypress.Commands.add("createUser", email => { // quick hacky recorded way to create a user cy.contains("Users").click() - cy.get(".spectrum-Button--primary").click() + cy.get(`[data-cy="add-user"]`).click() cy.get(".spectrum-Picker-label").click() cy.get(".spectrum-Menu-item:nth-child(2) > .spectrum-Menu-itemLabel").click() + + //Onboarding type selector cy.get( ":nth-child(2) > .spectrum-Form-itemField > .spectrum-Textfield > .spectrum-Textfield-input" ) @@ -312,16 +340,46 @@ Cypress.Commands.add("addCustomSourceOptions", totalOptions => { }) }) +//Filters visible with 1 or more Cypress.Commands.add("searchForApplication", appName => { - cy.wait(1000) - // Searches for the app - cy.get(".filter").then(() => { - cy.get(".spectrum-Textfield").within(() => { - cy.get("input").eq(0).type(appName) + cy.visit(`${Cypress.config().baseUrl}/builder`) + cy.wait(2000) + + // No app filter functionality if only 1 app exists + cy.request(`${Cypress.config().baseUrl}/api/applications?status=all`) + .its("body") + .then(val => { + if (val.length < 2) { + return + } else { + // Searches for the app + cy.get(".filter").then(() => { + cy.get(".spectrum-Textfield").within(() => { + cy.get("input").eq(0).clear() + cy.get("input").eq(0).type(appName) + }) + }) + } }) +}) + +//Assumes there are no others +Cypress.Commands.add("applicationInAppTable", appName => { + cy.get(".appTable").within(() => { + cy.get(".title").contains(appName).should("exist") }) - // Confirms app exists after search - cy.get(".appTable").contains(appName) +}) + +Cypress.Commands.add("createAppFromScratch", appName => { + cy.get(`[data-cy="create-app-btn"]`) + .contains("Start from scratch") + .click({ force: true }) + cy.get(".spectrum-Modal").within(() => { + cy.get("input").eq(0).type(appName).should("have.value", appName).blur() + cy.get(".spectrum-ButtonGroup").contains("Create app").click() + cy.wait(10000) + }) + cy.createTable("Cypress Tests", true) }) Cypress.Commands.add("selectExternalDatasource", datasourceName => { diff --git a/packages/builder/package.json b/packages/builder/package.json index 8b8172516b..6dde63596e 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "1.0.91-alpha.17", + "version": "1.0.105-alpha.10", "license": "GPL-3.0", "private": true, "scripts": { @@ -65,10 +65,10 @@ } }, "dependencies": { - "@budibase/bbui": "^1.0.91-alpha.17", - "@budibase/client": "^1.0.91-alpha.17", - "@budibase/frontend-core": "^1.0.91-alpha.17", - "@budibase/string-templates": "^1.0.91-alpha.17", + "@budibase/bbui": "^1.0.105-alpha.10", + "@budibase/client": "^1.0.105-alpha.10", + "@budibase/frontend-core": "^1.0.105-alpha.10", + "@budibase/string-templates": "^1.0.105-alpha.10", "@sentry/browser": "5.19.1", "@spectrum-css/page": "^3.0.1", "@spectrum-css/vars": "^3.0.1", diff --git a/packages/builder/src/builderStore/dataBinding.js b/packages/builder/src/builderStore/dataBinding.js index 41174a9d9d..8dff56dd6b 100644 --- a/packages/builder/src/builderStore/dataBinding.js +++ b/packages/builder/src/builderStore/dataBinding.js @@ -7,7 +7,11 @@ import { getComponentSettings, } from "./componentUtils" import { store } from "builderStore" -import { queries as queriesStores, tables as tablesStore } from "stores/backend" +import { + queries as queriesStores, + tables as tablesStore, + roles as rolesStore, +} from "stores/backend" import { makePropSafe, isJSBinding, @@ -33,6 +37,7 @@ export const getBindableProperties = (asset, componentId) => { const deviceBindings = getDeviceBindings() const stateBindings = getStateBindings() const selectedRowsBindings = getSelectedRowsBindings(asset) + const roleBindings = getRoleBindings() return [ ...contextBindings, ...urlBindings, @@ -40,6 +45,7 @@ export const getBindableProperties = (asset, componentId) => { ...userBindings, ...deviceBindings, ...selectedRowsBindings, + ...roleBindings, ] } @@ -391,20 +397,57 @@ const getUrlBindings = asset => { })) } +const getRoleBindings = () => { + return (get(rolesStore) || []).map(role => { + return { + type: "context", + runtimeBinding: `trim "${role._id}"`, + readableBinding: `Role.${role.name}`, + } + }) +} + /** * Gets all bindable properties exposed in a button actions flow up until - * the specified action ID. + * the specified action ID, as well as context provided for the action + * setting as a whole by the component. */ -export const getButtonContextBindings = (actions, actionId) => { +export const getButtonContextBindings = ( + asset, + componentId, + settingKey, + actions, + actionId +) => { + let bindings = [] + + // Check if any context bindings are provided by the component for this + // setting + const component = findComponent(asset.props, componentId) + const settings = getComponentSettings(component?._component) + const eventSetting = settings.find(setting => setting.key === settingKey) + if (!eventSetting) { + return bindings + } + if (eventSetting.context?.length) { + eventSetting.context.forEach(contextEntry => { + bindings.push({ + readableBinding: contextEntry.label, + runtimeBinding: `${makePropSafe("eventContext")}.${makePropSafe( + contextEntry.key + )}`, + }) + }) + } + // Get the steps leading up to this value const index = actions?.findIndex(action => action.id === actionId) if (index == null || index === -1) { - return [] + return bindings } const prevActions = actions.slice(0, index) // Generate bindings for any steps which provide context - let bindings = [] prevActions.forEach((action, idx) => { const def = ActionDefinitions.actions.find( x => x.name === action["##eventHandlerType"] @@ -418,6 +461,7 @@ export const getButtonContextBindings = (actions, actionId) => { }) } }) + return bindings } diff --git a/packages/builder/src/builderStore/store/frontend.js b/packages/builder/src/builderStore/store/frontend.js index 3d824767b5..836e4c3d24 100644 --- a/packages/builder/src/builderStore/store/frontend.js +++ b/packages/builder/src/builderStore/store/frontend.js @@ -45,6 +45,7 @@ const INITIAL_FRONTEND_STATE = { customThemes: false, devicePreview: false, messagePassing: false, + continueIfAction: false, }, currentFrontEndType: "none", selectedScreenId: "", diff --git a/packages/builder/src/builderStore/store/screenTemplates/utils/sanitizeUrl.js b/packages/builder/src/builderStore/store/screenTemplates/utils/sanitizeUrl.js index 16224a45bc..4d00c503fb 100644 --- a/packages/builder/src/builderStore/store/screenTemplates/utils/sanitizeUrl.js +++ b/packages/builder/src/builderStore/store/screenTemplates/utils/sanitizeUrl.js @@ -2,9 +2,15 @@ export default function (url) { return url .split("/") .map(part => { - // if parameter, then use as is - if (part.startsWith(":")) return part - return encodeURIComponent(part.replace(/ /g, "-")) + part = decodeURIComponent(part) + part = part.replace(/ /g, "-") + + // If parameter, then use as is + if (!part.startsWith(":")) { + part = encodeURIComponent(part) + } + + return part }) .join("/") .toLowerCase() diff --git a/packages/builder/src/builderStore/store/theme.js b/packages/builder/src/builderStore/store/theme.js index d4d7460ed2..bd3a149d63 100644 --- a/packages/builder/src/builderStore/store/theme.js +++ b/packages/builder/src/builderStore/store/theme.js @@ -2,9 +2,10 @@ import { createLocalStorageStore } from "@budibase/frontend-core" export const getThemeStore = () => { const themeElement = document.documentElement + const initialValue = { theme: "darkest", - options: ["lightest", "light", "dark", "darkest"], + options: ["lightest", "light", "dark", "darkest", "nord"], } const store = createLocalStorageStore("bb-theme", initialValue) @@ -21,6 +22,7 @@ export const getThemeStore = () => { `spectrum--${option}`, option === state.theme ) + themeElement.classList.add("spectrum--darkest") }) }) diff --git a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte index a94a78286c..3d857ec9fb 100644 --- a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte +++ b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte @@ -162,7 +162,7 @@ diff --git a/packages/builder/src/components/common/bindings/ServerBindingPanel.svelte b/packages/builder/src/components/common/bindings/ServerBindingPanel.svelte index 5440ba0b18..213e5bbf1d 100644 --- a/packages/builder/src/components/common/bindings/ServerBindingPanel.svelte +++ b/packages/builder/src/components/common/bindings/ServerBindingPanel.svelte @@ -12,8 +12,8 @@ const enrichBindings = bindings => { return bindings?.map(binding => ({ ...binding, - readableBinding: binding.label || binding.readableBinding, - runtimeBinding: binding.path || binding.runtimeBinding, + readableBinding: binding.readableBinding || binding.label, + runtimeBinding: binding.runtimeBinding || binding.path, })) } diff --git a/packages/builder/src/components/design/NavigationPanel/ComponentNavigationTree/index.svelte b/packages/builder/src/components/design/NavigationPanel/ComponentNavigationTree/index.svelte index 1c108f164e..ed064f8307 100644 --- a/packages/builder/src/components/design/NavigationPanel/ComponentNavigationTree/index.svelte +++ b/packages/builder/src/components/design/NavigationPanel/ComponentNavigationTree/index.svelte @@ -3,13 +3,14 @@ import PathTree from "./PathTree.svelte" let routes = {} - $: paths = Object.keys(routes || {}).sort() + let paths = [] - $: { - const allRoutes = $store.routes + $: allRoutes = $store.routes + $: selectedScreenId = $store.selectedScreenId + $: updatePaths(allRoutes, $selectedAccessRole, selectedScreenId) + + const updatePaths = (allRoutes, selectedRoleId, selectedScreenId) => { const sortedPaths = Object.keys(allRoutes || {}).sort() - const selectedRoleId = $selectedAccessRole - const selectedScreenId = $store.selectedScreenId let found = false let firstValidScreenId @@ -41,11 +42,15 @@ }) }) }) - routes = filteredRoutes + routes = { ...filteredRoutes } + paths = Object.keys(routes || {}).sort() // Select the correct role for the current screen ID if (!found && screenRoleId) { selectedAccessRole.set(screenRoleId) + if (screenRoleId !== selectedRoleId) { + updatePaths(allRoutes, screenRoleId, selectedScreenId) + } } // If the selected screen isn't in this filtered list, select the first one diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/ButtonActionDrawer.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/ButtonActionDrawer.svelte index 8cf0f37f70..5b0ab4a6a3 100644 --- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/ButtonActionDrawer.svelte +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/ButtonActionDrawer.svelte @@ -12,11 +12,13 @@ import { getAvailableActions } from "./index" import { generate } from "shortid" import { getButtonContextBindings } from "builderStore/dataBinding" + import { currentAsset, store } from "builderStore" const flipDurationMs = 150 const EVENT_TYPE_KEY = "##eventHandlerType" const actionTypes = getAvailableActions() + export let key export let actions export let bindings = [] @@ -24,6 +26,9 @@ // These are ephemeral bindings which only exist while executing actions $: buttonContextBindings = getButtonContextBindings( + $currentAsset, + $store.selectedComponentId, + key, actions, selectedAction?.id ) diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/ButtonActionEditor.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/ButtonActionEditor.svelte index 6a0e94cd4c..550d982013 100644 --- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/ButtonActionEditor.svelte +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/ButtonActionEditor.svelte @@ -8,6 +8,7 @@ const dispatch = createEventDispatcher() + export let key export let value = [] export let name export let bindings @@ -81,5 +82,6 @@ bind:actions={tmpValue} eventType={name} {bindings} + {key} /> diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/actions/ContinueIf.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/actions/ContinueIf.svelte new file mode 100644 index 0000000000..f284e24645 --- /dev/null +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/actions/ContinueIf.svelte @@ -0,0 +1,78 @@ + + +
+ + Configure a condition to be evaluated which can stop further actions from + being executed. + + + (parameters.referenceValue = e.detail)} + {bindings} + /> +
+ + diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/actions/TriggerAutomation.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/actions/TriggerAutomation.svelte index e5b4c9d108..fa32c88d65 100644 --- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/actions/TriggerAutomation.svelte +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/actions/TriggerAutomation.svelte @@ -19,7 +19,7 @@ .filter(a => a.definition.trigger?.stepId === "APP") .map(automation => { const schema = Object.entries( - automation.definition.trigger.inputs.fields + automation.definition.trigger.inputs.fields || {} ).map(([name, type]) => ({ name, type })) return { diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/actions/index.js b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/actions/index.js index 6593c9cbd4..2306d4a548 100644 --- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/actions/index.js +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/actions/index.js @@ -13,3 +13,4 @@ export { default as RefreshDataProvider } from "./RefreshDataProvider.svelte" export { default as DuplicateRow } from "./DuplicateRow.svelte" export { default as S3Upload } from "./S3Upload.svelte" export { default as ExportData } from "./ExportData.svelte" +export { default as ContinueIf } from "./ContinueIf.svelte" diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/manifest.json b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/manifest.json index 0f6d3344b2..80464b281f 100644 --- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/manifest.json +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/ButtonActionEditor/manifest.json @@ -84,6 +84,11 @@ { "name": "Export Data", "component": "ExportData" + }, + { + "name": "Continue if / Stop if", + "component": "ContinueIf", + "dependsOnFeature": "continueIfAction" } ] -} \ No newline at end of file +} diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/PropertyControl.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/PropertyControl.svelte index 911688b30c..617b1c83ab 100644 --- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/PropertyControl.svelte +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/PropertyControl.svelte @@ -79,6 +79,7 @@ bindings={allBindings} name={key} text={label} + {key} {type} {...props} /> diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/RoleSelect.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/RoleSelect.svelte index be6fc8cb12..9571cf9a92 100644 --- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/RoleSelect.svelte +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/RoleSelect.svelte @@ -3,6 +3,7 @@ import { roles } from "stores/backend" export let value + export let error ($validation.touched.url = true)} - label="URL" - placeholder={$values.name - ? "/" + encodeURIComponent($values.name).toLowerCase() - : "/"} - /> + + ($validation.touched.url = true)} + on:change={tidyUrl($values.url)} + label="URL" + placeholder={$values.url + ? $values.url + : `/${resolveAppUrl(template, $values.name)}`} + /> + {#if $values.url && $values.url !== "" && !$validation.errors.url} +
+ {appUrl} +
+ {/if} +
+ + diff --git a/packages/builder/src/components/start/UpdateAppModal.svelte b/packages/builder/src/components/start/UpdateAppModal.svelte index 1ce699b834..e6a40b23e8 100644 --- a/packages/builder/src/components/start/UpdateAppModal.svelte +++ b/packages/builder/src/components/start/UpdateAppModal.svelte @@ -42,11 +42,31 @@ } } - // auto add slash to url - $: { - if ($values.url && !$values.url.startsWith("/")) { - $values.url = `/${$values.url}` + const resolveAppUrl = (template, name) => { + let parsedName + const resolvedName = resolveAppName(null, name) + parsedName = resolvedName ? resolvedName.toLowerCase() : "" + const parsedUrl = parsedName ? parsedName.replace(/\s+/g, "-") : "" + return encodeURI(parsedUrl) + } + + const resolveAppName = (template, name) => { + if (template && !name) { + return template.name } + return name ? name.trim() : null + } + + const tidyUrl = url => { + if (url && !url.startsWith("/")) { + url = `/${url}` + } + $values.url = url === "" ? null : url + } + + const nameToUrl = appName => { + let resolvedUrl = resolveAppUrl(null, appName) + tidyUrl(resolvedUrl) } @@ -61,15 +81,17 @@ bind:value={$values.name} error={$validation.touched.name && $validation.errors.name} on:blur={() => ($validation.touched.name = true)} + on:change={nameToUrl($values.name)} label="Name" /> ($validation.touched.url = true)} + on:change={tidyUrl($values.url)} label="URL" - placeholder={$values.name - ? "/" + encodeURIComponent($values.name).toLowerCase() - : "/"} + placeholder={$values.url + ? $values.url + : `/${resolveAppUrl(null, $values.name)}`} /> diff --git a/packages/builder/src/helpers/validation/yup/app.js b/packages/builder/src/helpers/validation/yup/app.js index de0f86446c..4e41576d46 100644 --- a/packages/builder/src/helpers/validation/yup/app.js +++ b/packages/builder/src/helpers/validation/yup/app.js @@ -35,13 +35,14 @@ export const url = (validation, { apps, currentApp } = { apps: [] }) => { validation.addValidator( "url", string() + .trim() .nullable() - .matches(APP_URL_REGEX, "App URL must not contain spaces") + .required("Your application must have a url") + .matches(APP_URL_REGEX, "Please enter a valid url") .test( "non-existing-app-url", "Another app with the same URL already exists", value => { - // url is nullable if (!value) { return true } diff --git a/packages/builder/src/pages/builder/portal/apps/create.svelte b/packages/builder/src/pages/builder/portal/apps/create.svelte new file mode 100644 index 0000000000..cf1e3b66bd --- /dev/null +++ b/packages/builder/src/pages/builder/portal/apps/create.svelte @@ -0,0 +1,151 @@ + + + + + + + + +
+
+ + {createAppTitle} + + {welcomeBody} + + + +
+ + +
+
+
+ + + + {#if loaded && $templates?.length} + + {/if} +
+
+ + + + + + diff --git a/packages/builder/src/pages/builder/portal/apps/index.svelte b/packages/builder/src/pages/builder/portal/apps/index.svelte index f582e80842..0337662b40 100644 --- a/packages/builder/src/pages/builder/portal/apps/index.svelte +++ b/packages/builder/src/pages/builder/portal/apps/index.svelte @@ -11,8 +11,9 @@ notifications, Body, Search, - Icon, + Divider, } from "@budibase/bbui" + import TemplateDisplay from "components/common/TemplateDisplay.svelte" import Spinner from "components/common/Spinner.svelte" import CreateAppModal from "components/start/CreateAppModal.svelte" import UpdateAppModal from "components/start/UpdateAppModal.svelte" @@ -39,12 +40,27 @@ let unpublishModal let iconModal let creatingApp = false - let loaded = false + let loaded = $apps?.length || $templates?.length let searchTerm = "" let cloud = $admin.cloud let appName = "" let creatingFromTemplate = false + const resolveWelcomeMessage = (auth, apps) => { + const userWelcome = auth?.user?.firstName + ? `Welcome ${auth?.user?.firstName}!` + : "Welcome back!" + return apps?.length ? userWelcome : "Let's create your first app!" + } + $: welcomeHeader = resolveWelcomeMessage($auth, $apps) + $: welcomeBody = $apps?.length + ? "Manage your apps and get a head start with templates" + : "Start from scratch or get a head start with one of our templates" + + $: createAppButtonText = $apps?.length + ? "Create new app" + : "Start from scratch" + $: enrichedApps = enrichApps($apps, $auth.user, sortBy) $: filteredApps = enrichedApps.filter(app => app?.name?.toLowerCase().includes(searchTerm.toLowerCase()) @@ -79,9 +95,13 @@ } const initiateAppCreation = () => { - template = null - creationModal.show() - creatingApp = true + if ($apps?.length) { + $goto("/builder/portal/apps/create") + } else { + template = null + creationModal.show() + creatingApp = true + } } const initiateAppsExport = () => { @@ -269,148 +289,120 @@ -
- - Welcome to Budibase - - Manage your apps and get a head start with templates - - + {#if loaded} +
+
+ + {welcomeHeader} + + {welcomeBody} + + -
- {#if cloud} - - {/if} - - -
-
- - - Quick start templates -
- {#each $templates as item} -
{ - template = item - creationModal.show() - creatingApp = true - }} - class="template-card" - > - + + {#if $apps?.length > 0} + + {/if} + {#if !$apps?.length} + + {/if} +
+
+
+ + + +
+ +
+ + {#if !$apps?.length && $templates?.length} + + {/if} + + {#if enrichedApps.length} + +
+ Apps + {#if enrichedApps.length > 1} +
+ {#if cloud} + + {/if} +
+ - +
+ {#each filteredApps as app (app.appId)} + + {/each}
-
- -
- {#each filteredApps as app (app.appId)} - - {/each} -
- - {/if} - - {#if !enrichedApps.length && !creatingApp && loaded} -
-
-
- - logo -
- Create a business app in minutes! -
- -
-
-
-
+ + {/if} {/if} {#if creatingFromTemplate}
+

Creating your Budibase app from your selected template...

@@ -460,6 +452,15 @@ diff --git a/packages/builder/src/pages/builder/portal/apps/templates.svelte b/packages/builder/src/pages/builder/portal/apps/templates.svelte new file mode 100644 index 0000000000..477380d4c9 --- /dev/null +++ b/packages/builder/src/pages/builder/portal/apps/templates.svelte @@ -0,0 +1,43 @@ + + + + + + + + {#if loaded && $templates?.length} + + {/if} + + diff --git a/packages/builder/src/pages/builder/portal/manage/users/index.svelte b/packages/builder/src/pages/builder/portal/manage/users/index.svelte index 1160cc109b..bfbe520b2f 100644 --- a/packages/builder/src/pages/builder/portal/manage/users/index.svelte +++ b/packages/builder/src/pages/builder/portal/manage/users/index.svelte @@ -71,7 +71,9 @@ Users - +
diff --git a/packages/builder/yarn.lock b/packages/builder/yarn.lock index 48fd25ac71..29b0481072 100644 --- a/packages/builder/yarn.lock +++ b/packages/builder/yarn.lock @@ -4424,9 +4424,9 @@ minimatch@^3.0.4: brace-expansion "^1.1.7" minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== mixin-deep@^1.2.0: version "1.3.2" diff --git a/packages/cli/package.json b/packages/cli/package.json index 0520aa1416..ccfe05f86e 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "1.0.91-alpha.17", + "version": "1.0.105-alpha.10", "description": "Budibase CLI, for developers, self hosting and migrations.", "main": "src/index.js", "bin": { diff --git a/packages/cli/yarn.lock b/packages/cli/yarn.lock index 5aba4810ca..39fc4ed990 100644 --- a/packages/cli/yarn.lock +++ b/packages/cli/yarn.lock @@ -1123,9 +1123,9 @@ minimatch@^3.0.4: brace-expansion "^1.1.7" minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3: version "0.5.3" diff --git a/packages/client/manifest.json b/packages/client/manifest.json index be718ed271..4c3c0faf1f 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -7,7 +7,8 @@ "customThemes": true, "devicePreview": true, "messagePassing": true, - "rowSelection": true + "rowSelection": true, + "continueIfAction": true }, "layout": { "name": "Layout", @@ -2528,69 +2529,103 @@ "name": "Embedded Map", "icon": "Location", "styles": ["size"], - "editable": true, "draggable": false, - "illegalChildren": [ - "section" - ], + "illegalChildren": ["section"], "settings": [ { "type": "dataProvider", "label": "Provider", "key": "dataProvider" }, + { + "type": "field", + "label": "Latitude Key", + "key": "latitudeKey", + "dependsOn": "dataProvider" + }, + { + "type": "field", + "label": "Longitude Key", + "key": "longitudeKey", + "dependsOn": "dataProvider" + }, + { + "type": "field", + "label": "Title Key", + "key": "titleKey", + "dependsOn": "dataProvider" + }, + { + "type": "event", + "label": "On Click Marker", + "key": "onClickMarker", + "context": [ + { + "label": "Clicked marker", + "key": "marker" + } + ] + }, { "type": "boolean", - "label": "Enable Fullscreen", + "label": "Enable creating markers", + "key": "creationEnabled", + "defaultValue": false + }, + { + "type": "event", + "label": "On Create Marker", + "key": "onCreateMarker", + "dependsOn": "creationEnabled", + "context": [ + { + "label": "New marker latitude", + "key": "lat" + }, + { + "label": "New marker longitude", + "key": "lng" + } + ] + }, + { + "type": "boolean", + "label": "Enable fullscreen", "key": "fullScreenEnabled", "defaultValue": true }, { "type": "boolean", - "label": "Enable Location", + "label": "Enable location", "key": "locationEnabled", "defaultValue": true }, { "type": "boolean", - "label": "Enable Zoom", + "label": "Enable zoom", "key": "zoomEnabled", "defaultValue": true }, - { - "type": "number", - "label": "Zoom Level (0-100)", - "key": "zoomLevel", - "defaultValue": 72, - "max" : 100, - "min" : 0 - }, - { - "type": "field", - "label": "Latitude Key", - "key": "latitudeKey" - }, - { - "type": "field", - "label": "Longitude Key", - "key": "longitudeKey" - }, - { - "type": "field", - "label": "Title Key", - "key": "titleKey" - }, { "type": "text", "label": "Tile URL", "key": "tileURL", "defaultValue": "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" }, + { "type": "text", - "label": "Default Location (lat,lng)", + "label": "Default Location (when empty)", "key": "defaultLocation", - "defaultValue": "51.5072,-0.1276" + "placeholder": "51.5072,-0.1276" + }, + { + "type": "number", + "label": "Default Location Zoom Level (0-100)", + "key": "zoomLevel", + "placeholder": 50, + "max": 100, + "min": 0 }, { "type": "text", @@ -3595,7 +3630,6 @@ "name": "Markdown Viewer", "icon": "TaskList", "styles": ["size"], - "editable": true, "settings": [ { "type": "text", diff --git a/packages/client/package.json b/packages/client/package.json index fb0e893e05..264aa57fe5 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "1.0.91-alpha.17", + "version": "1.0.105-alpha.10", "license": "MPL-2.0", "module": "dist/budibase-client.js", "main": "dist/budibase-client.js", @@ -19,9 +19,9 @@ "dev:builder": "rollup -cw" }, "dependencies": { - "@budibase/bbui": "^1.0.91-alpha.17", - "@budibase/frontend-core": "^1.0.91-alpha.17", - "@budibase/string-templates": "^1.0.91-alpha.17", + "@budibase/bbui": "^1.0.105-alpha.10", + "@budibase/frontend-core": "^1.0.105-alpha.10", + "@budibase/string-templates": "^1.0.105-alpha.10", "@spectrum-css/button": "^3.0.3", "@spectrum-css/card": "^3.0.3", "@spectrum-css/divider": "^1.0.3", diff --git a/packages/client/src/components/Component.svelte b/packages/client/src/components/Component.svelte index e4176587ee..d9af295108 100644 --- a/packages/client/src/components/Component.svelte +++ b/packages/client/src/components/Component.svelte @@ -1,6 +1,7 @@ - +{#key $component.editing} + +{/key} diff --git a/packages/client/src/components/app/embedded-map/EmbeddedMap.svelte b/packages/client/src/components/app/embedded-map/EmbeddedMap.svelte index 200aaaaed9..7738a0d345 100644 --- a/packages/client/src/components/app/embedded-map/EmbeddedMap.svelte +++ b/packages/client/src/components/app/embedded-map/EmbeddedMap.svelte @@ -2,8 +2,8 @@ import L from "leaflet" import sanitizeHtml from "sanitize-html" import "leaflet/dist/leaflet.css" - import { Helpers } from "@budibase/bbui" - import { getContext } from "svelte" + import { Helpers, Button } from "@budibase/bbui" + import { onMount, getContext } from "svelte" import { FullScreenControl, LocationControl, @@ -24,86 +24,16 @@ export let defaultLocation export let tileURL = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" export let mapAttribution + export let creationEnabled = false + export let onClickMarker + export let onCreateMarker const { styleable, notificationStore } = getContext("sdk") const component = getContext("component") const embeddedMapId = `${Helpers.uuid()}-wrapper` - let cachedDeviceCoordinates - const fallbackCoordinates = [51.5072, -0.1276] //London - - let mapInstance - let mapMarkerGroup = new L.FeatureGroup() - let mapMarkers = [] - - let minZoomLevel = 0 - let maxZoomLevel = 18 - let adjustedZoomLevel = !Number.isInteger(zoomLevel) - ? 72 - : Math.round(zoomLevel * (maxZoomLevel / 100)) - - $: zoomControlUpdated(mapInstance, zoomEnabled) - $: locationControlUpdated(mapInstance, locationEnabled) - $: fullScreenControlUpdated(mapInstance, fullScreenEnabled) - $: updateMapDimensions( - mapInstance, - $component.styles.normal.width, - $component.styles.normal.height - ) - $: addMapMarkers( - mapInstance, - dataProvider?.rows, - latitudeKey, - longitudeKey, - titleKey - ) - $: if (typeof mapInstance === "object" && mapMarkers.length > 0) { - mapInstance.setZoom(0) - mapInstance.fitBounds(mapMarkerGroup.getBounds(), { - paddingTopLeft: [0, 24], - }) - } - - const updateMapDimensions = mapInstance => { - if (typeof mapInstance !== "object") { - return - } - mapInstance.invalidateSize() - } - - let isValidLatitude = value => { - return !isNaN(value) && value > -90 && value < 90 - } - - let isValidLongitude = value => { - return !isNaN(value) && value > -180 && value < 180 - } - - const parseDefaultLocation = defaultLocation => { - if (typeof defaultLocation !== "string") { - return fallbackCoordinates - } - let defaultLocationParts = defaultLocation.split(",") - if (defaultLocationParts.length !== 2) { - return fallbackCoordinates - } - - let parsedDefaultLatitude = parseFloat(defaultLocationParts[0].trim()) - let parsedDefaultLongitude = parseFloat(defaultLocationParts[1].trim()) - - return isValidLatitude(parsedDefaultLatitude) === true && - isValidLongitude(parsedDefaultLongitude) === true - ? [parsedDefaultLatitude, parsedDefaultLongitude] - : fallbackCoordinates - } - - $: defaultCoordinates = - mapMarkers.length > 0 - ? parseDefaultLocation(defaultLocation) - : fallbackCoordinates - // Map Button Controls - let locationControl = new LocationControl({ + const locationControl = new LocationControl({ position: "bottomright", onLocationFail: err => { if (err.code === GeolocationPositionError.PERMISSION_DENIED) { @@ -129,13 +59,135 @@ } }, }) - let fullScreenControl = new FullScreenControl({ + const fullScreenControl = new FullScreenControl({ position: "topright", }) - let zoomControl = L.control.zoom({ + const zoomControl = L.control.zoom({ position: "bottomright", }) + // Map and marker configuration + const defaultMarkerOptions = { + html: + '
' + + '
', + className: "embedded-map-marker", + iconSize: [26, 26], + iconAnchor: [13, 26], + popupAnchor: [0, -13], + } + const mapMarkerOptions = { + icon: L.divIcon(defaultMarkerOptions), + draggable: false, + alt: "Location Marker", + } + const candidateMarkerOptions = { + icon: L.divIcon({ + ...defaultMarkerOptions, + className: "embedded-map-marker--candidate", + }), + draggable: false, + alt: "Location Marker", + } + const mapOptions = { + fullScreen: false, + zoomControl: false, + scrollWheelZoom: zoomEnabled, + minZoomLevel, + maxZoomLevel, + } + const fallbackCoordinates = [51.5072, -0.1276] //London + + let mapInstance + let mapMarkerGroup = new L.FeatureGroup() + let candidateMarkerGroup = new L.FeatureGroup() + let candidateMarkerPosition + let mounted = false + let initialMarkerZoomCompleted = false + let minZoomLevel = 0 + let maxZoomLevel = 18 + let cachedDeviceCoordinates + + $: validRows = getValidRows(dataProvider?.rows, latitudeKey, longitudeKey) + $: safeZoomLevel = parseZoomLevel(zoomLevel) + $: defaultCoordinates = parseDefaultLocation(defaultLocation) + $: initMap(tileURL, mapAttribution, safeZoomLevel) + $: zoomControlUpdated(mapInstance, zoomEnabled) + $: locationControlUpdated(mapInstance, locationEnabled) + $: fullScreenControlUpdated(mapInstance, fullScreenEnabled) + $: width = $component.styles.normal.width + $: height = $component.styles.normal.height + $: width, height, mapInstance?.invalidateSize() + $: defaultCoordinates, resetView() + $: addMapMarkers( + mapInstance, + validRows, + latitudeKey, + longitudeKey, + titleKey, + onClickMarker + ) + + const isValidLatitude = value => { + return !isNaN(value) && value > -90 && value < 90 + } + + const isValidLongitude = value => { + return !isNaN(value) && value > -180 && value < 180 + } + + const getValidRows = (rows, latKey, lngKey) => { + if (!rows?.length || !latKey || !lngKey) { + return [] + } + return rows.filter(row => { + return isValidLatitude(row[latKey]) && isValidLongitude(row[lngKey]) + }) + } + + const parseZoomLevel = zoomLevel => { + let zoom = zoomLevel + if (zoom == null || isNaN(zoom)) { + zoom = 50 + } else { + zoom = parseFloat(zoom) + zoom = Math.max(0, Math.min(100, zoom)) + } + return Math.round((zoom * maxZoomLevel) / 100) + } + + const parseDefaultLocation = defaultLocation => { + if (typeof defaultLocation !== "string") { + return fallbackCoordinates + } + let defaultLocationParts = defaultLocation.split(",") + if (defaultLocationParts.length !== 2) { + return fallbackCoordinates + } + + let parsedDefaultLatitude = parseFloat(defaultLocationParts[0].trim()) + let parsedDefaultLongitude = parseFloat(defaultLocationParts[1].trim()) + + return isValidLatitude(parsedDefaultLatitude) === true && + isValidLongitude(parsedDefaultLongitude) === true + ? [parsedDefaultLatitude, parsedDefaultLongitude] + : fallbackCoordinates + } + + const resetView = () => { + if (!mapInstance) { + return + } + if (mapMarkerGroup.getLayers().length) { + mapInstance.setZoom(0) + mapInstance.fitBounds(mapMarkerGroup.getBounds(), { + paddingTopLeft: [0, 24], + }) + } else { + mapInstance.setView(defaultCoordinates, safeZoomLevel) + } + } + const locationControlUpdated = (mapInstance, locationEnabled) => { if (typeof mapInstance !== "object") { return @@ -171,44 +223,25 @@ } } - //Map icon and marker configuration - const mapIconMarkup = - '
' + - '
' - const mapIcon = L.divIcon({ - html: mapIconMarkup, - className: "embedded-map-marker", - iconSize: [26, 26], - iconAnchor: [13, 26], - popupAnchor: [0, -13], - }) - const mapMarkerOptions = { - icon: mapIcon, - draggable: false, - alt: "Location Marker", - } - let mapOptions = { - fullScreen: false, - zoomControl: false, - scrollWheelZoom: zoomEnabled, - minZoomLevel, - maxZoomLevel, - } - - const addMapMarkers = (mapInstance, rows, latKey, lngKey, titleKey) => { - if (typeof mapInstance !== "object" || !rows || !latKey || !lngKey) { + const addMapMarkers = ( + mapInstance, + validRows, + latKey, + lngKey, + titleKey, + onClick + ) => { + if (!mapInstance) { return } mapMarkerGroup.clearLayers() - - const validRows = rows.filter(row => { - return isValidLatitude(row[latKey]) && isValidLongitude(row[lngKey]) - }) + if (!validRows?.length) { + return + } validRows.forEach(row => { let markerCoords = [row[latKey], row[lngKey]] - let marker = L.marker(markerCoords, mapMarkerOptions).addTo(mapInstance) let markerContent = generateMarkerPopupContent( row[latKey], @@ -216,52 +249,105 @@ row[titleKey] ) - marker.bindPopup(markerContent).addTo(mapMarkerGroup) + marker + .bindTooltip(markerContent, { + direction: "top", + offset: [0, -25], + }) + .addTo(mapMarkerGroup) - //https://github.com/Leaflet/Leaflet/issues/7331 - marker.on("click", function () { - this.openPopup() - }) - - mapMarkers = [...mapMarkers, marker] + if (onClick) { + marker.on("click", () => { + onClick({ + marker: row, + }) + }) + } }) + + // Zoom to markers if this is the first time + if (!initialMarkerZoomCompleted) { + resetView() + initialMarkerZoomCompleted = true + } } const generateMarkerPopupContent = (latitude, longitude, text) => { return text || latitude + "," + longitude } - const initMap = () => { - const initCoords = defaultCoordinates - + const initMap = (tileURL, attribution, zoom) => { + if (!mounted) { + return + } + if (mapInstance) { + mapInstance.remove() + } mapInstance = L.map(embeddedMapId, mapOptions) mapMarkerGroup.addTo(mapInstance) + candidateMarkerGroup.addTo(mapInstance) - const cleanAttribution = sanitizeHtml(mapAttribution, { + // Add attribution + const cleanAttribution = sanitizeHtml(attribution, { allowedTags: ["a"], allowedAttributes: { a: ["href", "target"], }, }) - L.tileLayer(tileURL, { attribution: "© " + cleanAttribution, - zoom: adjustedZoomLevel, + zoom, }).addTo(mapInstance) - //Initialise the map - mapInstance.setView(initCoords, adjustedZoomLevel) + // Add click handler + mapInstance.on("click", handleMapClick) + + // Reset view + resetView() } - const mapAction = () => { - initMap() - return { - destroy() { - mapInstance.remove() - mapInstance = undefined - }, + const handleMapClick = e => { + if (!creationEnabled) { + return + } + candidateMarkerGroup.clearLayers() + candidateMarkerPosition = [e.latlng.lat, e.latlng.lng] + let candidateMarker = L.marker( + candidateMarkerPosition, + candidateMarkerOptions + ) + candidateMarker + .bindTooltip("New marker", { + permanent: true, + direction: "top", + offset: [0, -25], + }) + .addTo(candidateMarkerGroup) + .on("click", clearCandidateMarker) + } + + const createMarker = async () => { + if (!onCreateMarker) { + return + } + const res = await onCreateMarker({ + lat: candidateMarkerPosition[0], + lng: candidateMarkerPosition[1], + }) + if (res !== false) { + clearCandidateMarker() } } + + const clearCandidateMarker = () => { + candidateMarkerGroup.clearLayers() + candidateMarkerPosition = null + } + + onMount(() => { + mounted = true + initMap(tileURL, mapAttribution, safeZoomLevel) + })
@@ -269,12 +355,20 @@
{error}
{/if} -
+
+ + {#if candidateMarkerPosition} +
+ + +
+ {/if}
diff --git a/packages/client/src/components/app/forms/Field.svelte b/packages/client/src/components/app/forms/Field.svelte index ca7bd3caaf..3ebfc5084f 100644 --- a/packages/client/src/components/app/forms/Field.svelte +++ b/packages/client/src/components/app/forms/Field.svelte @@ -50,22 +50,24 @@ $: labelClass = labelPos === "above" ? "" : `spectrum-FieldLabel--${labelPos}` const updateLabel = e => { - builderStore.actions.updateProp("label", e.target.textContent.trim()) + builderStore.actions.updateProp("label", e.target.textContent) }
- + {#key $component.editing} + + {/key}
{#if !formContext} diff --git a/packages/client/src/components/app/forms/Form.svelte b/packages/client/src/components/app/forms/Form.svelte index 8e2e0b2510..740c5fd9f1 100644 --- a/packages/client/src/components/app/forms/Form.svelte +++ b/packages/client/src/components/app/forms/Form.svelte @@ -9,6 +9,10 @@ export let disabled = false export let actionType = "Create" + // Not exposed as a builder setting. Used internally to disable validation + // for fields rendered in things like search blocks. + export let disableValidation = false + const context = getContext("context") const { API, fetchDatasourceSchema } = getContext("sdk") @@ -102,6 +106,7 @@ {schema} {table} {initialValues} + {disableValidation} > diff --git a/packages/client/src/components/app/forms/InnerForm.svelte b/packages/client/src/components/app/forms/InnerForm.svelte index b82070681b..ae6ae3ebcc 100644 --- a/packages/client/src/components/app/forms/InnerForm.svelte +++ b/packages/client/src/components/app/forms/InnerForm.svelte @@ -10,6 +10,7 @@ export let size export let schema export let table + export let disableValidation = false const component = getContext("component") const { styleable, Provider, ActionTypes } = getContext("sdk") @@ -141,12 +142,14 @@ // Create validation function based on field schema const schemaConstraints = schema?.[field]?.constraints - const validator = createValidatorFromConstraints( - schemaConstraints, - validationRules, - field, - table - ) + const validator = disableValidation + ? null + : createValidatorFromConstraints( + schemaConstraints, + validationRules, + field, + table + ) // If we've already registered this field then keep some existing state let initialValue = Helpers.deepGet(initialValues, field) ?? defaultValue @@ -164,7 +167,7 @@ // If this field has already been registered and we previously had an // error set, then re-run the validator to see if we can unset it if (fieldState.error) { - initialError = validator(initialValue) + initialError = validator?.(initialValue) } } @@ -254,7 +257,7 @@ } // Update field state - const error = validator ? validator(value) : null + const error = validator?.(value) fieldInfo.update(state => { state.fieldState.value = value state.fieldState.error = error @@ -288,12 +291,14 @@ // Create new validator const schemaConstraints = schema?.[field]?.constraints - const validator = createValidatorFromConstraints( - schemaConstraints, - validationRules, - field, - table - ) + const validator = disableValidation + ? null + : createValidatorFromConstraints( + schemaConstraints, + validationRules, + field, + table + ) // Update validator fieldInfo.update(state => { diff --git a/packages/client/src/components/overlay/PeekScreenDisplay.svelte b/packages/client/src/components/overlay/PeekScreenDisplay.svelte index 72ea58c194..d6da9ca3f0 100644 --- a/packages/client/src/components/overlay/PeekScreenDisplay.svelte +++ b/packages/client/src/components/overlay/PeekScreenDisplay.svelte @@ -20,8 +20,8 @@ let listenersAttached = false const proxyInvalidation = event => { - const { dataSourceId } = event.detail - dataSourceStore.actions.invalidateDataSource(dataSourceId) + const { dataSourceId, options } = event.detail + dataSourceStore.actions.invalidateDataSource(dataSourceId, options) } const proxyNotification = event => { diff --git a/packages/client/src/components/preview/SettingsBar.svelte b/packages/client/src/components/preview/SettingsBar.svelte index c5ad8bef6c..05df1ef898 100644 --- a/packages/client/src/components/preview/SettingsBar.svelte +++ b/packages/client/src/components/preview/SettingsBar.svelte @@ -66,6 +66,11 @@ newTop = deviceBottom - 44 } + //If element is at the very top of the screen, put the bar below the element + if (elBounds.top < elBounds.height) { + newTop = elBounds.bottom + verticalOffset + } + // Horizontally, try to center first. // Failing that, render to left edge of component. // Failing that, render to right edge of component, diff --git a/packages/client/src/stores/confirmation.js b/packages/client/src/stores/confirmation.js index 497b021b04..bb9a54386f 100644 --- a/packages/client/src/stores/confirmation.js +++ b/packages/client/src/stores/confirmation.js @@ -4,30 +4,36 @@ const initialState = { showConfirmation: false, title: null, text: null, - callback: null, + onConfirm: null, + onCancel: null, } const createConfirmationStore = () => { const store = writable(initialState) - const showConfirmation = (title, text, callback) => { + const showConfirmation = (title, text, onConfirm, onCancel) => { store.set({ showConfirmation: true, title, text, - callback, + onConfirm, + onCancel, }) } const confirm = async () => { const state = get(store) - if (!state.showConfirmation || !state.callback) { + if (!state.showConfirmation || !state.onConfirm) { return } store.set(initialState) - await state.callback() + await state.onConfirm() } const cancel = () => { + const state = get(store) store.set(initialState) + if (state.onCancel) { + state.onCancel() + } } return { diff --git a/packages/client/src/stores/dataSource.js b/packages/client/src/stores/dataSource.js index d5ad0cb594..6288cbc072 100644 --- a/packages/client/src/stores/dataSource.js +++ b/packages/client/src/stores/dataSource.js @@ -54,18 +54,24 @@ export const createDataSourceStore = () => { // Invalidates a specific dataSource ID by refreshing all instances // which depend on data from that dataSource - const invalidateDataSource = async dataSourceId => { + const invalidateDataSource = async (dataSourceId, options) => { if (!dataSourceId) { return } + // Merge default options + options = { + invalidateRelationships: false, + ...options, + } + // Emit this as a window event, so parent screens which are iframing us in // can also invalidate the same datasource const inModal = get(routeStore).queryParams?.peek if (inModal) { window.parent.postMessage({ type: "invalidate-datasource", - detail: { dataSourceId }, + detail: { dataSourceId, options }, }) } @@ -73,13 +79,14 @@ export const createDataSourceStore = () => { // Fetch related table IDs from table schema let schema - try { - const definition = await API.fetchTableDefinition(dataSourceId) - schema = definition?.schema - } catch (error) { - schema = null + if (options.invalidateRelationships) { + try { + const definition = await API.fetchTableDefinition(dataSourceId) + schema = definition?.schema + } catch (error) { + schema = null + } } - if (schema) { Object.values(schema).forEach(fieldSchema => { if ( diff --git a/packages/client/src/utils/buttonActions.js b/packages/client/src/utils/buttonActions.js index f44e7d7453..f851a623c0 100644 --- a/packages/client/src/utils/buttonActions.js +++ b/packages/client/src/utils/buttonActions.js @@ -37,7 +37,9 @@ const saveRowHandler = async (action, context) => { notificationStore.actions.success("Row saved") // Refresh related datasources - await dataSourceStore.actions.invalidateDataSource(row.tableId) + await dataSourceStore.actions.invalidateDataSource(row.tableId, { + invalidateRelationships: true, + }) return { row } } catch (error) { @@ -65,7 +67,9 @@ const duplicateRowHandler = async (action, context) => { notificationStore.actions.success("Row saved") // Refresh related datasources - await dataSourceStore.actions.invalidateDataSource(row.tableId) + await dataSourceStore.actions.invalidateDataSource(row.tableId, { + invalidateRelationships: true, + }) return { row } } catch (error) { @@ -83,7 +87,9 @@ const deleteRowHandler = async action => { notificationStore.actions.success("Row deleted") // Refresh related datasources - await dataSourceStore.actions.invalidateDataSource(tableId) + await dataSourceStore.actions.invalidateDataSource(tableId, { + invalidateRelationships: true, + }) } catch (error) { // Abort next actions return false @@ -261,6 +267,26 @@ const exportDataHandler = async action => { } } +const continueIfHandler = action => { + const { type, value, operator, referenceValue } = action.parameters + if (!type || !operator) { + return + } + let match = false + if (value == null && referenceValue == null) { + match = true + } else if (value === referenceValue) { + match = true + } else { + match = JSON.stringify(value) === JSON.stringify(referenceValue) + } + if (type === "continue") { + return operator === "equal" ? match : !match + } else { + return operator === "equal" ? !match : match + } +} + const handlerMap = { ["Save Row"]: saveRowHandler, ["Duplicate Row"]: duplicateRowHandler, @@ -277,6 +303,7 @@ const handlerMap = { ["Update State"]: updateStateHandler, ["Upload File to S3"]: s3UploadHandler, ["Export Data"]: exportDataHandler, + ["Continue if / Stop if"]: continueIfHandler, } const confirmTextMap = { @@ -302,13 +329,13 @@ export const enrichButtonActions = (actions, context) => { return actions } - // Button context is built up as actions are executed. - // Inherit any previous button context which may have come from actions - // before a confirmable action since this breaks the chain. - let buttonContext = context.actions || [] - const handlers = actions.map(def => handlerMap[def["##eventHandlerType"]]) - return async () => { + return async eventContext => { + // Button context is built up as actions are executed. + // Inherit any previous button context which may have come from actions + // before a confirmable action since this breaks the chain. + let buttonContext = context.actions || [] + for (let i = 0; i < handlers.length; i++) { try { // Skip any non-existent action definitions @@ -317,7 +344,12 @@ export const enrichButtonActions = (actions, context) => { } // Built total context for this action - const totalContext = { ...context, actions: buttonContext } + const totalContext = { + ...context, + state: get(stateStore), + actions: buttonContext, + eventContext, + } // Get and enrich this button action with the total context let action = actions[i] @@ -327,33 +359,36 @@ export const enrichButtonActions = (actions, context) => { // If this action is confirmable, show confirmation and await a // callback to execute further actions if (action.parameters?.confirm) { - const defaultText = confirmTextMap[action["##eventHandlerType"]] - const confirmText = action.parameters?.confirmText || defaultText - confirmationStore.actions.showConfirmation( - action["##eventHandlerType"], - confirmText, - async () => { - // When confirmed, execute this action immediately, - // then execute the rest of the actions in the chain - const result = await callback() - if (result !== false) { - // Generate a new total context to pass into the next enrichment - buttonContext.push(result) - const newContext = { ...context, actions: buttonContext } + return new Promise(resolve => { + const defaultText = confirmTextMap[action["##eventHandlerType"]] + const confirmText = action.parameters?.confirmText || defaultText + confirmationStore.actions.showConfirmation( + action["##eventHandlerType"], + confirmText, + async () => { + // When confirmed, execute this action immediately, + // then execute the rest of the actions in the chain + const result = await callback() + if (result !== false) { + // Generate a new total context to pass into the next enrichment + buttonContext.push(result) + const newContext = { ...context, actions: buttonContext } - // Enrich and call the next button action - const next = enrichButtonActions( - actions.slice(i + 1), - newContext - ) - await next() + // Enrich and call the next button action + const next = enrichButtonActions( + actions.slice(i + 1), + newContext + ) + resolve(await next()) + } else { + resolve(false) + } + }, + () => { + resolve(false) } - } - ) - - // Stop enriching actions when encountering a confirmable action, - // as the callback continues the action chain - return + ) + }) } // For non-confirmable actions, execute the handler immediately diff --git a/packages/client/src/utils/componentProps.js b/packages/client/src/utils/componentProps.js index 0727b5943f..14760252a9 100644 --- a/packages/client/src/utils/componentProps.js +++ b/packages/client/src/utils/componentProps.js @@ -22,7 +22,7 @@ export const propsAreSame = (a, b) => { * Enriches component props. * Data bindings are enriched, and button actions are enriched. */ -export const enrichProps = (props, context) => { +export const enrichProps = (props, context, settingsDefinitionMap) => { // Create context of all bindings and data contexts // Duplicate the closest context as "data" which the builder requires const totalContext = { @@ -38,7 +38,7 @@ export const enrichProps = (props, context) => { let normalProps = { ...props } let actionProps = {} Object.keys(normalProps).forEach(prop => { - if (prop?.toLowerCase().includes("onclick")) { + if (settingsDefinitionMap?.[prop]?.type === "event") { actionProps[prop] = normalProps[prop] delete normalProps[prop] } @@ -61,7 +61,7 @@ export const enrichProps = (props, context) => { // Conditions if (enrichedProps._conditions?.length) { enrichedProps._conditions.forEach((condition, idx) => { - if (condition.setting?.toLowerCase().includes("onclick")) { + if (settingsDefinitionMap?.[condition.setting]?.type === "event") { // Use the original condition action value to enrich it to a button // action condition.settingValue = enrichButtonActions( diff --git a/packages/frontend-core/package.json b/packages/frontend-core/package.json index bfda35cc66..b37208d97d 100644 --- a/packages/frontend-core/package.json +++ b/packages/frontend-core/package.json @@ -1,12 +1,12 @@ { "name": "@budibase/frontend-core", - "version": "1.0.91-alpha.17", + "version": "1.0.105-alpha.10", "description": "Budibase frontend core libraries used in builder and client", "author": "Budibase", "license": "MPL-2.0", "svelte": "src/index.js", "dependencies": { - "@budibase/bbui": "^1.0.91-alpha.17", + "@budibase/bbui": "^1.0.105-alpha.10", "lodash": "^4.17.21", "svelte": "^3.46.2" } diff --git a/packages/server/.eslintrc b/packages/server/.eslintrc deleted file mode 100644 index a4ad9fdb55..0000000000 --- a/packages/server/.eslintrc +++ /dev/null @@ -1,13 +0,0 @@ -{ - "globals": { - "emit": true, - "key": true - }, - "parser": "@typescript-eslint/parser", - "env": { - "node": true - }, - "extends": ["eslint:recommended"], - "rules": { - } -} \ No newline at end of file diff --git a/packages/server/package.json b/packages/server/package.json index 72bb61c456..11d1ebf4bc 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "1.0.91-alpha.17", + "version": "1.0.105-alpha.10", "description": "Budibase Web Server", "main": "src/index.ts", "repository": { @@ -21,10 +21,7 @@ "dev:stack:down": "node scripts/dev/manage.js down", "dev:stack:nuke": "node scripts/dev/manage.js nuke", "dev:builder": "yarn run dev:stack:up && nodemon", - "format": "prettier --config ../../.prettierrc.json 'src/**/*.ts' --write", "specs": "node specs/generate.js && openapi-typescript specs/openapi.yaml --output src/definitions/openapi.ts", - "lint": "eslint --fix src/", - "lint:fix": "yarn run format && yarn run lint", "initialise": "node scripts/initialise.js", "env:multi:enable": "node scripts/multiTenancy.js enable", "env:multi:disable": "node scripts/multiTenancy.js disable", @@ -71,9 +68,9 @@ "license": "GPL-3.0", "dependencies": { "@apidevtools/swagger-parser": "^10.0.3", - "@budibase/backend-core": "^1.0.91-alpha.17", - "@budibase/client": "^1.0.91-alpha.17", - "@budibase/string-templates": "^1.0.91-alpha.17", + "@budibase/backend-core": "^1.0.105-alpha.10", + "@budibase/client": "^1.0.105-alpha.10", + "@budibase/string-templates": "^1.0.105-alpha.10", "@bull-board/api": "^3.7.0", "@bull-board/koa": "^3.7.0", "@elastic/elasticsearch": "7.10.0", diff --git a/packages/server/scripts/integrations/customer-categories/docker-compose.yml b/packages/server/scripts/integrations/customer-categories/docker-compose.yml index 4dfcb0e1ad..069033001b 100644 --- a/packages/server/scripts/integrations/customer-categories/docker-compose.yml +++ b/packages/server/scripts/integrations/customer-categories/docker-compose.yml @@ -3,7 +3,7 @@ services: db: container_name: postgres image: postgres - restart: always + restart: unless-stopped environment: POSTGRES_USER: root POSTGRES_PASSWORD: root @@ -17,7 +17,7 @@ services: pgadmin: container_name: pgadmin-pg image: dpage/pgadmin4 - restart: always + restart: unless-stopped environment: PGADMIN_DEFAULT_EMAIL: root@root.com PGADMIN_DEFAULT_PASSWORD: root diff --git a/packages/server/scripts/integrations/mysql/init.sql b/packages/server/scripts/integrations/mysql/init.sql index f37ef0d532..9fa608f42d 100644 --- a/packages/server/scripts/integrations/mysql/init.sql +++ b/packages/server/scripts/integrations/mysql/init.sql @@ -14,6 +14,7 @@ CREATE TABLE Tasks ( TaskID int NOT NULL AUTO_INCREMENT, PersonID INT, TaskName varchar(255), + CreatedAt DATE, PRIMARY KEY (TaskID), CONSTRAINT fkPersons FOREIGN KEY(PersonID) @@ -25,6 +26,6 @@ CREATE TABLE Products ( updated time ); INSERT INTO Persons (FirstName, LastName, Age, Address, City, CreatedAt) VALUES ('Mike', 'Hughes', 28.2, '123 Fake Street', 'Belfast', '2021-01-19 03:14:07'); -INSERT INTO Tasks (PersonID, TaskName) VALUES (1, 'assembling'); -INSERT INTO Tasks (PersonID, TaskName) VALUES (1, 'processing'); +INSERT INTO Tasks (PersonID, TaskName, CreatedAt) VALUES (1, 'assembling', '2020-01-01'); +INSERT INTO Tasks (PersonID, TaskName, CreatedAt) VALUES (2, 'processing', '2019-12-31'); INSERT INTO Products (name, updated) VALUES ('Meat', '11:00:22'), ('Fruit', '10:00:00'); diff --git a/packages/server/scripts/integrations/oracle/docker-compose.yml b/packages/server/scripts/integrations/oracle/docker-compose.yml index c54cd0a40b..15b4c16eee 100644 --- a/packages/server/scripts/integrations/oracle/docker-compose.yml +++ b/packages/server/scripts/integrations/oracle/docker-compose.yml @@ -4,7 +4,7 @@ version: "3.8" services: db: - restart: always + restart: unless-stopped platform: linux/x86_64 image: container-registry.oracle.com/database/express:18.4.0-xe environment: diff --git a/packages/server/scripts/integrations/postgres/docker-compose.yml b/packages/server/scripts/integrations/postgres/docker-compose.yml index 2323025e5e..d682ad7361 100644 --- a/packages/server/scripts/integrations/postgres/docker-compose.yml +++ b/packages/server/scripts/integrations/postgres/docker-compose.yml @@ -3,7 +3,7 @@ services: db: container_name: postgres image: postgres - restart: always + restart: unless-stopped environment: POSTGRES_USER: root POSTGRES_PASSWORD: root @@ -17,7 +17,7 @@ services: pgadmin: container_name: pgadmin-pg image: dpage/pgadmin4 - restart: always + restart: unless-stopped environment: PGADMIN_DEFAULT_EMAIL: root@root.com PGADMIN_DEFAULT_PASSWORD: root diff --git a/packages/server/scripts/integrations/service-vehicles/docker-compose.yml b/packages/server/scripts/integrations/service-vehicles/docker-compose.yml index 7473e540db..96141d14d8 100644 --- a/packages/server/scripts/integrations/service-vehicles/docker-compose.yml +++ b/packages/server/scripts/integrations/service-vehicles/docker-compose.yml @@ -3,7 +3,7 @@ services: db: container_name: postgres-vehicle image: postgres - restart: always + restart: unless-stopped environment: POSTGRES_USER: root POSTGRES_PASSWORD: root @@ -17,7 +17,7 @@ services: pgadmin: container_name: pgadmin image: dpage/pgadmin4 - restart: always + restart: unless-stopped environment: PGADMIN_DEFAULT_EMAIL: root@root.com PGADMIN_DEFAULT_PASSWORD: root diff --git a/packages/server/specs/openapi.json b/packages/server/specs/openapi.json index 6ca1a5b9fb..30ef0a8c6f 100644 --- a/packages/server/specs/openapi.json +++ b/packages/server/specs/openapi.json @@ -1260,10 +1260,30 @@ ] }, "executeQuery": { - "description": "The query body must contain the required parameters for the query, this depends on query type, setup and bindings.", + "description": "The parameters required for executing a query.", "type": "object", - "additionalProperties": { - "description": "Key value properties of any type, depending on the query output schema." + "properties": { + "parameters": { + "type": "object", + "description": "This contains the required parameters for the query, this depends on query type, setup and bindings.", + "additionalProperties": { + "description": "Key value properties of any type, depending on the query output schema." + } + }, + "pagination": { + "type": "object", + "description": "For supported query types (currently on REST) pagination can be performed using these properties.", + "properties": { + "page": { + "type": "string", + "description": "The page which has been returned from a previous query." + }, + "limit": { + "type": "number", + "description": "The number of rows to return per page." + } + } + } } }, "executeQueryOutput": { diff --git a/packages/server/specs/openapi.yaml b/packages/server/specs/openapi.yaml index c4d9808c86..ed55df953a 100644 --- a/packages/server/specs/openapi.yaml +++ b/packages/server/specs/openapi.yaml @@ -951,11 +951,27 @@ components: required: - data executeQuery: - description: The query body must contain the required parameters for the query, - this depends on query type, setup and bindings. + description: The parameters required for executing a query. type: object - additionalProperties: - description: Key value properties of any type, depending on the query output schema. + properties: + parameters: + type: object + description: This contains the required parameters for the query, this depends + on query type, setup and bindings. + additionalProperties: + description: Key value properties of any type, depending on the query output + schema. + pagination: + type: object + description: For supported query types (currently on REST) pagination can be + performed using these properties. + properties: + page: + type: string + description: The page which has been returned from a previous query. + limit: + type: number + description: The number of rows to return per page. executeQueryOutput: type: object properties: diff --git a/packages/server/specs/resources/query.js b/packages/server/specs/resources/query.js index df532c9a3a..d4a4882fb2 100644 --- a/packages/server/specs/resources/query.js +++ b/packages/server/specs/resources/query.js @@ -124,12 +124,34 @@ const querySchema = object( ) const executeQuerySchema = { - description: - "The query body must contain the required parameters for the query, this depends on query type, setup and bindings.", + description: "The parameters required for executing a query.", type: "object", - additionalProperties: { - description: - "Key value properties of any type, depending on the query output schema.", + properties: { + parameters: { + type: "object", + description: + "This contains the required parameters for the query, this depends on query type, setup and bindings.", + additionalProperties: { + description: + "Key value properties of any type, depending on the query output schema.", + }, + }, + pagination: { + type: "object", + description: + "For supported query types (currently on REST) pagination can be performed using these properties.", + properties: { + page: { + type: "string", + description: + "The page which has been returned from a previous query.", + }, + limit: { + type: "number", + description: "The number of rows to return per page.", + }, + }, + }, }, } diff --git a/packages/server/src/api/controllers/auth.js b/packages/server/src/api/controllers/auth.js index 30c0e5d09c..03480f62fb 100644 --- a/packages/server/src/api/controllers/auth.js +++ b/packages/server/src/api/controllers/auth.js @@ -7,7 +7,7 @@ const { getAppDB, getAppId } = require("@budibase/backend-core/context") exports.fetchSelf = async ctx => { let userId = ctx.user.userId || ctx.user._id /* istanbul ignore next */ - if (!userId) { + if (!userId || !ctx.isAuthenticated) { ctx.body = {} return } diff --git a/packages/server/src/api/controllers/integration.js b/packages/server/src/api/controllers/integration.js index 75fd9ce80e..f3f3309c02 100644 --- a/packages/server/src/api/controllers/integration.js +++ b/packages/server/src/api/controllers/integration.js @@ -1,8 +1,24 @@ +const { cloneDeep } = require("lodash") const { definitions } = require("../../integrations") +const { getTenantId } = require("@budibase/backend-core/tenancy") +const { SourceNames } = require("../../definitions/datasource") +const googlesheets = require("../../integrations/googlesheets") +const env = require("../../environment") exports.fetch = async function (ctx) { ctx.status = 200 - ctx.body = definitions + const defs = cloneDeep(definitions) + + // for google sheets integration google verification + if (env.EXCLUDE_QUOTAS_TENANTS) { + const excludedTenants = env.EXCLUDE_QUOTAS_TENANTS.split(",") + const tenantId = getTenantId() + if (excludedTenants.includes(tenantId)) { + defs[SourceNames.GOOGLE_SHEETS] = googlesheets.schema + } + } + + ctx.body = defs } exports.find = async function (ctx) { diff --git a/packages/server/src/api/controllers/permission.js b/packages/server/src/api/controllers/permission.js index 0e37a3e7d3..e1547eb597 100644 --- a/packages/server/src/api/controllers/permission.js +++ b/packages/server/src/api/controllers/permission.js @@ -4,6 +4,7 @@ const { getDBRoleID, getExternalRoleID, getBuiltinRoles, + checkForRoleResourceArray, } = require("@budibase/backend-core/roles") const { getRoleParams } = require("../../db/utils") const { @@ -144,12 +145,11 @@ exports.getResourcePerms = async function (ctx) { for (let level of SUPPORTED_LEVELS) { // update the various roleIds in the resource permissions for (let role of roles) { - const rolePerms = role.permissions + const rolePerms = checkForRoleResourceArray(role.permissions, resourceId) if ( rolePerms && rolePerms[resourceId] && - (rolePerms[resourceId] === level || - rolePerms[resourceId].indexOf(level) !== -1) + rolePerms[resourceId].indexOf(level) !== -1 ) { permissions[level] = getExternalRoleID(role._id) } diff --git a/packages/server/src/api/controllers/static/index.js b/packages/server/src/api/controllers/static/index.js index 73790db3ac..bcd12172dd 100644 --- a/packages/server/src/api/controllers/static/index.js +++ b/packages/server/src/api/controllers/static/index.js @@ -5,7 +5,6 @@ const { resolve, join } = require("../../../utilities/centralPath") const uuid = require("uuid") const { ObjectStoreBuckets } = require("../../../constants") const { processString } = require("@budibase/string-templates") -const { getAllApps } = require("@budibase/backend-core/db") const { loadHandlebarsFile, NODE_MODULES_PATH, @@ -16,7 +15,7 @@ const { clientLibraryPath } = require("../../../utilities") const { upload } = require("../../../utilities/fileSystem") const { attachmentsRelativeURL } = require("../../../utilities") const { DocumentTypes, isDevAppID } = require("../../../db/utils") -const { getAppDB, updateAppId } = require("@budibase/backend-core/context") +const { getAppDB, getAppId } = require("@budibase/backend-core/context") const AWS = require("aws-sdk") const AWS_REGION = env.AWS_REGION ? env.AWS_REGION : "eu-west-1" const { events } = require("@budibase/backend-core") @@ -41,21 +40,6 @@ async function prepareUpload({ s3Key, bucket, metadata, file }) { } } -async function getAppIdFromUrl(ctx) { - // the "appId" component of the URL can be the id or the custom url - let possibleAppUrl = `/${encodeURI(ctx.params.appId).toLowerCase()}` - - // search prod apps for a url that matches, exclude dev where id is always used - const apps = await getAllApps({ dev: false }) - const app = apps.filter( - a => a.url && a.url.toLowerCase() === possibleAppUrl - )[0] - - const appId = app && app.appId ? app.appId : ctx.params.appId - updateAppId(appId) - return appId -} - exports.serveBuilder = async function (ctx) { let builderPath = resolve(TOP_LEVEL_PATH, "builder") await send(ctx, ctx.file, { root: builderPath }) @@ -84,9 +68,9 @@ exports.uploadFile = async function (ctx) { } exports.serveApp = async function (ctx) { - let appId = await getAppIdFromUrl(ctx) const db = getAppDB({ skip_setup: true }) const appInfo = await db.get(DocumentTypes.APP_METADATA) + let appId = getAppId() if (!env.isJest()) { const App = require("./templates/BudibaseApp.svelte").default diff --git a/packages/server/src/api/controllers/table/external.js b/packages/server/src/api/controllers/table/external.js index f61a31dac1..5a7239e90c 100644 --- a/packages/server/src/api/controllers/table/external.js +++ b/packages/server/src/api/controllers/table/external.js @@ -119,8 +119,8 @@ function generateManyLinkSchema(datasource, column, table, relatedTable) { }, } column.through = junctionTable._id - column.throughFrom = primary - column.throughTo = relatedPrimary + column.throughFrom = relatedPrimary + column.throughTo = primary column.fieldName = relatedPrimary return junctionTable } @@ -147,7 +147,7 @@ function generateRelatedSchema(linkColumn, table, relatedTable, columnName) { // is many to many else { // don't need to copy through, already got it - relatedSchema.fieldName = linkColumn.throughFrom + relatedSchema.fieldName = linkColumn.throughTo relatedSchema.throughTo = linkColumn.throughFrom relatedSchema.throughFrom = linkColumn.throughTo } diff --git a/packages/server/src/api/index.js b/packages/server/src/api/index.js index 582bb1eef9..b1e8341457 100644 --- a/packages/server/src/api/index.js +++ b/packages/server/src/api/index.js @@ -3,7 +3,6 @@ const { buildAuthMiddleware, auditLog, buildTenancyMiddleware, - buildAppTenancyMiddleware, } = require("@budibase/backend-core/auth") const { errors } = require("@budibase/backend-core") const currentApp = require("../middleware/currentapp") @@ -16,6 +15,9 @@ const { middleware: pro } = require("@budibase/pro") const router = new Router() +router.get("/health", ctx => (ctx.status = 200)) +router.get("/version", ctx => (ctx.body = pkg.version)) + router .use( compress({ @@ -36,8 +38,6 @@ router } await next() }) - .use("/health", ctx => (ctx.status = 200)) - .use("/version", ctx => (ctx.body = pkg.version)) // re-direct before any middlewares occur .redirect("/", "/builder") .use( @@ -54,8 +54,6 @@ router }) ) .use(currentApp) - // this middleware will try to use the app ID to determine the tenancy - .use(buildAppTenancyMiddleware()) .use(pro.licensing()) .use(auditLog) @@ -77,8 +75,6 @@ router.use(async (ctx, next) => { } }) -router.get("/health", ctx => (ctx.status = 200)) - // authenticated routes for (let route of mainRoutes) { router.use(route.routes()) diff --git a/packages/server/src/api/routes/static.ts b/packages/server/src/api/routes/static.ts index 5db279b41a..d216d993b4 100644 --- a/packages/server/src/api/routes/static.ts +++ b/packages/server/src/api/routes/static.ts @@ -44,8 +44,8 @@ router authorized(PermissionTypes.TABLE, PermissionLevels.WRITE), controller.uploadFile ) - // TODO: this likely needs to be secured in some way .get("/:appId/:path*", controller.serveApp) + .get("/app/:appUrl/:path*", controller.serveApp) .post( "/api/attachments/:datasourceId/url", authorized(PermissionTypes.TABLE, PermissionLevels.READ), diff --git a/packages/server/src/api/routes/table.js b/packages/server/src/api/routes/table.js index 4d20b98962..5d2378710d 100644 --- a/packages/server/src/api/routes/table.js +++ b/packages/server/src/api/routes/table.js @@ -40,7 +40,7 @@ router .get( "/api/tables/:tableId", paramResource("tableId"), - authorized(PermissionTypes.TABLE, PermissionLevels.READ), + authorized(PermissionTypes.TABLE, PermissionLevels.READ, { schema: true }), tableController.find ) /** diff --git a/packages/server/src/api/routes/tests/static.spec.js b/packages/server/src/api/routes/tests/static.spec.js index d0a89d1fa4..d5e5486cce 100644 --- a/packages/server/src/api/routes/tests/static.spec.js +++ b/packages/server/src/api/routes/tests/static.spec.js @@ -14,7 +14,7 @@ jest.mock("aws-sdk", () => ({ })) const setup = require("./utilities") -const { events } = require("@budibase/backend-core") +const { events, constants } = require("@budibase/backend-core") const version = require("../../../../package.json").version describe("/static", () => { @@ -49,9 +49,12 @@ describe("/static", () => { }) it("should serve the app by id", async () => { + const headers = config.defaultHeaders() + delete headers[constants.Headers.APP_ID] + const res = await request .get(`/${config.prodAppId}`) - .set(config.defaultHeaders()) + .set(headers) .expect(200) expect(res.body.appId).toBe(config.prodAppId) @@ -61,9 +64,12 @@ describe("/static", () => { }) it("should serve the app by url", async () => { + const headers = config.defaultHeaders() + delete headers[constants.Headers.APP_ID] + const res = await request - .get(`${config.prodApp.url}`) - .set(config.defaultHeaders()) + .get(`/app${config.prodApp.url}`) + .set(headers) .expect(200) expect(res.body.appId).toBe(config.prodAppId) diff --git a/packages/server/src/automations/steps/queryRows.js b/packages/server/src/automations/steps/queryRows.js index 5bc19d0022..62f7659589 100644 --- a/packages/server/src/automations/steps/queryRows.js +++ b/packages/server/src/automations/steps/queryRows.js @@ -85,7 +85,7 @@ exports.run = async function ({ inputs, appId }) { const { tableId, filters, sortColumn, sortOrder, limit } = inputs const table = await getTable(appId, tableId) let sortType = FieldTypes.STRING - if (table && table.schema && sortColumn) { + if (table && table.schema && table.schema[sortColumn] && sortColumn) { const fieldType = table.schema[sortColumn].type sortType = fieldType === FieldTypes.NUMBER ? FieldTypes.NUMBER : FieldTypes.STRING diff --git a/packages/server/src/automations/utils.ts b/packages/server/src/automations/utils.ts index ac73ea932b..3724a6d370 100644 --- a/packages/server/src/automations/utils.ts +++ b/packages/server/src/automations/utils.ts @@ -17,12 +17,12 @@ const Runner = new Thread(ThreadType.AUTOMATION) export async function processEvent(job: any) { try { + console.log( + `${job.data.automation.appId} automation ${job.data.automation._id} running` + ) + // need to actually await these so that an error can be captured properly const tenantId = tenancy.getTenantIDFromAppID(job.data.event.appId) return await tenancy.doInTenant(tenantId, async () => { - console.log( - `${job.data.automation.appId} automation ${job.data.automation._id} running` - ) - // need to actually await these so that an error can be captured properly const runFn = () => Runner.run(job) return quotas.addAutomation(runFn) }) @@ -31,6 +31,7 @@ export async function processEvent(job: any) { console.error( `${job.data.automation.appId} automation ${job.data.automation._id} was unable to run - ${errJson}` ) + console.trace(err) return { err } } } diff --git a/packages/server/src/db/views/staticViews.js b/packages/server/src/db/views/staticViews.js index fa0b1f3605..5cfae746df 100644 --- a/packages/server/src/db/views/staticViews.js +++ b/packages/server/src/db/views/staticViews.js @@ -33,6 +33,7 @@ exports.createLinkView = async () => { if (doc.type === "link") { let doc1 = doc.doc1 let doc2 = doc.doc2 + // eslint-disable-next-line no-undef emit([doc1.tableId, doc1.rowId], { id: doc2.rowId, thisId: doc1.rowId, @@ -40,6 +41,7 @@ exports.createLinkView = async () => { }) // if linking to same table can't emit twice if (doc1.tableId !== doc2.tableId) { + // eslint-disable-next-line no-undef emit([doc2.tableId, doc2.rowId], { id: doc1.rowId, thisId: doc2.rowId, diff --git a/packages/server/src/definitions/datasource.ts b/packages/server/src/definitions/datasource.ts index 88115237a0..4df08683f0 100644 --- a/packages/server/src/definitions/datasource.ts +++ b/packages/server/src/definitions/datasource.ts @@ -182,11 +182,7 @@ export interface QueryJson { export interface SqlQuery { sql: string - bindings?: - | string[] - | { - [key: string]: any - } + bindings?: string[] } export interface QueryOptions { diff --git a/packages/server/src/definitions/openapi.ts b/packages/server/src/definitions/openapi.ts index 532869069b..0fef60f4a0 100644 --- a/packages/server/src/definitions/openapi.ts +++ b/packages/server/src/definitions/openapi.ts @@ -932,11 +932,21 @@ export interface components { } } /** @description The ID of the table. */ - _id: string - }[] - } - /** @description The query body must contain the required parameters for the query, this depends on query type, setup and bindings. */ - executeQuery: { [key: string]: unknown } + _id: string; + }[]; + }; + /** @description The parameters required for executing a query. */ + executeQuery: { + /** @description This contains the required parameters for the query, this depends on query type, setup and bindings. */ + parameters?: { [key: string]: unknown }; + /** @description For supported query types (currently on REST) pagination can be performed using these properties. */ + pagination?: { + /** @description The page which has been returned from a previous query. */ + page?: string; + /** @description The number of rows to return per page. */ + limit?: number; + }; + }; executeQueryOutput: { /** @description The data response from the query. */ data: { [key: string]: unknown }[] diff --git a/packages/server/src/environment.js b/packages/server/src/environment.js index 60648b48b2..7a49409fa0 100644 --- a/packages/server/src/environment.js +++ b/packages/server/src/environment.js @@ -31,7 +31,7 @@ let inThread = false module.exports = { // important - PORT: process.env.PORT, + PORT: process.env.PORT || process.env.APP_PORT, JWT_SECRET: process.env.JWT_SECRET, COUCH_DB_URL: process.env.COUCH_DB_URL, MINIO_URL: process.env.MINIO_URL, @@ -47,6 +47,8 @@ module.exports = { MULTI_TENANCY: process.env.MULTI_TENANCY, HTTP_MIGRATIONS: process.env.HTTP_MIGRATIONS, API_REQ_LIMIT_PER_SEC: process.env.API_REQ_LIMIT_PER_SEC, + GOOGLE_CLIENT_ID: process.env.GOOGLE_CLIENT_ID, + GOOGLE_CLIENT_SECRET: process.env.GOOGLE_CLIENT_SECRET, // environment NODE_ENV: process.env.NODE_ENV, JEST_WORKER_ID: process.env.JEST_WORKER_ID, @@ -71,6 +73,7 @@ module.exports = { ALLOW_DEV_AUTOMATIONS: process.env.ALLOW_DEV_AUTOMATIONS, DISABLE_THREADING: process.env.DISABLE_THREADING, QUERY_THREAD_TIMEOUT: process.env.QUERY_THREAD_TIMEOUT, + SQL_MAX_ROWS: process.env.SQL_MAX_ROWS, _set(key, value) { process.env[key] = value module.exports[key] = value diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts index f4ebc02098..2e14eae870 100644 --- a/packages/server/src/integrations/base/sql.ts +++ b/packages/server/src/integrations/base/sql.ts @@ -9,8 +9,12 @@ import { } from "../../definitions/datasource" import { isIsoDateString, SqlClients } from "../utils" import SqlTableQueryBuilder from "./sqlTable" +import environment from "../../environment" -const BASE_LIMIT = 5000 +const envLimit = environment.SQL_MAX_ROWS + ? parseInt(environment.SQL_MAX_ROWS) + : null +const BASE_LIMIT = envLimit || 5000 type KnexQuery = Knex.QueryBuilder | Knex // these are invalid dates sent by the client, need to convert them to a real max date diff --git a/packages/server/src/integrations/dynamodb.ts b/packages/server/src/integrations/dynamodb.ts index 841dd6ff0d..be3668a08a 100644 --- a/packages/server/src/integrations/dynamodb.ts +++ b/packages/server/src/integrations/dynamodb.ts @@ -131,7 +131,9 @@ module DynamoModule { constructor(config: DynamoDBConfig) { this.config = config - this.connect() + if (!this.config.endpoint) { + this.connect() + } let options = { correctClockSkew: true, endpoint: config.endpoint ? config.endpoint : undefined, diff --git a/packages/server/src/integrations/googlesheets.ts b/packages/server/src/integrations/googlesheets.ts index bb2de26f5d..c58fdea551 100644 --- a/packages/server/src/integrations/googlesheets.ts +++ b/packages/server/src/integrations/googlesheets.ts @@ -10,6 +10,7 @@ import { Table, TableSchema } from "../definitions/common" import { buildExternalTableId } from "./utils" import { DataSourceOperation, FieldTypes } from "../constants" import { GoogleSpreadsheet } from "google-spreadsheet" +import env from "../environment" module GoogleSheetsModule { const { getGlobalDB } = require("@budibase/backend-core/tenancy") @@ -138,13 +139,27 @@ module GoogleSheetsModule { try { // Initialise oAuth client const db = getGlobalDB() - const googleConfig = await getScopedConfig(db, { + let googleConfig = await getScopedConfig(db, { type: Configs.GOOGLE, }) + + if (!googleConfig) { + googleConfig = { + clientID: env.GOOGLE_CLIENT_ID, + clientSecret: env.GOOGLE_CLIENT_SECRET, + } + } + const oauthClient = new OAuth2Client({ clientId: googleConfig.clientID, clientSecret: googleConfig.clientSecret, }) + oauthClient.on("tokens", tokens => { + oauthClient.setCredentials({ + refresh_token: googleConfig.refreshToken, + access_token: tokens.access_token, + }) + }) oauthClient.credentials.access_token = this.config.auth.accessToken oauthClient.credentials.refresh_token = this.config.auth.refreshToken this.client.useOAuth2Client(oauthClient) diff --git a/packages/server/src/integrations/index.ts b/packages/server/src/integrations/index.ts index 07f3211fcb..7408c6e001 100644 --- a/packages/server/src/integrations/index.ts +++ b/packages/server/src/integrations/index.ts @@ -26,7 +26,6 @@ const DEFINITIONS = { [SourceNames.MYSQL]: mysql.schema, [SourceNames.ARANGODB]: arangodb.schema, [SourceNames.REST]: rest.schema, - [SourceNames.FIREBASE]: firebase.schema, } const INTEGRATIONS = { @@ -42,6 +41,7 @@ const INTEGRATIONS = { [SourceNames.ARANGODB]: arangodb.integration, [SourceNames.REST]: rest.integration, [SourceNames.FIREBASE]: firebase.integration, + [SourceNames.GOOGLE_SHEETS]: googlesheets.integration, } // optionally add oracle integration if the oracle binary can be installed @@ -53,7 +53,6 @@ if (!(process.arch === "arm64" && process.platform === "darwin")) { if (environment.SELF_HOSTED) { DEFINITIONS[SourceNames.GOOGLE_SHEETS] = googlesheets.schema - INTEGRATIONS[SourceNames.GOOGLE_SHEETS] = googlesheets.integration } module.exports = { diff --git a/packages/server/src/integrations/mysql.ts b/packages/server/src/integrations/mysql.ts index 8b2c9ac944..cd5dc77f9b 100644 --- a/packages/server/src/integrations/mysql.ts +++ b/packages/server/src/integrations/mysql.ts @@ -14,6 +14,7 @@ import { finaliseExternalTables, } from "./utils" import { DatasourcePlus } from "./base/datasourcePlus" +import dayjs from "dayjs" module MySQLModule { const mysql = require("mysql2/promise") @@ -80,6 +81,26 @@ module MySQLModule { }, } + function bindingTypeCoerce(bindings: any[]) { + for (let i = 0; i < bindings.length; i++) { + const binding = bindings[i] + if (typeof binding !== "string") { + continue + } + const matches = binding.match(/^\d*$/g) + // check if number first + if (matches && matches[0] !== "" && !isNaN(Number(matches[0]))) { + bindings[i] = parseFloat(binding) + } + // if not a number, see if it is a date - important to do in this order as any + // integer will be considered a valid date + else if (dayjs(binding).isValid()) { + bindings[i] = dayjs(binding).toDate() + } + } + return bindings + } + class MySQLIntegration extends Sql implements DatasourcePlus { private config: MySQLConfig private client: any @@ -122,7 +143,7 @@ module MySQLModule { // Node MySQL is callback based, so we must wrap our call in a promise const response = await this.client.query( query.sql, - query.bindings || [] + bindingTypeCoerce(query.bindings || []) ) return response[0] } finally { diff --git a/packages/server/src/middleware/authorized.ts b/packages/server/src/middleware/authorized.ts index de80985aa3..272af7999c 100644 --- a/packages/server/src/middleware/authorized.ts +++ b/packages/server/src/middleware/authorized.ts @@ -5,6 +5,7 @@ import { } from "@budibase/backend-core/roles" const { PermissionTypes, + PermissionLevels, doesHaveBasePermission, } = require("@budibase/backend-core/permissions") const builderMiddleware = require("./builder") @@ -70,7 +71,7 @@ const checkAuthorizedResource = async ( } } -export = (permType: any, permLevel: any = null) => +export = (permType: any, permLevel: any = null, opts = { schema: false }) => async (ctx: any, next: any) => { // webhooks don't need authentication, each webhook unique // also internal requests (between services) don't need authorized @@ -87,15 +88,25 @@ export = (permType: any, permLevel: any = null) => await builderMiddleware(ctx, permType) // get the resource roles - let resourceRoles: any = [] + let resourceRoles = [], + otherLevelRoles + const otherLevel = + permLevel === PermissionLevels.READ + ? PermissionLevels.WRITE + : PermissionLevels.READ const appId = getAppId() if (appId && hasResource(ctx)) { resourceRoles = await getRequiredResourceRole(permLevel, ctx) + if (opts && opts.schema) { + otherLevelRoles = await getRequiredResourceRole(otherLevel, ctx) + } } // if the resource is public, proceed - const isPublicResource = resourceRoles.includes(BUILTIN_ROLE_IDS.PUBLIC) - if (isPublicResource) { + if ( + resourceRoles.includes(BUILTIN_ROLE_IDS.PUBLIC) || + (otherLevelRoles && otherLevelRoles.includes(BUILTIN_ROLE_IDS.PUBLIC)) + ) { return next() } @@ -104,8 +115,17 @@ export = (permType: any, permLevel: any = null) => return ctx.throw(403, "Session not authenticated") } - // check authorized - await checkAuthorized(ctx, resourceRoles, permType, permLevel) + try { + // check authorized + await checkAuthorized(ctx, resourceRoles, permType, permLevel) + } catch (err) { + // this is a schema, check if + if (opts && opts.schema && permLevel) { + await checkAuthorized(ctx, otherLevelRoles, permType, otherLevel) + } else { + throw err + } + } // csrf protection return csrf(ctx, next) diff --git a/packages/server/src/middleware/currentapp.js b/packages/server/src/middleware/currentapp.js index 70dd1bf578..bc9462759c 100644 --- a/packages/server/src/middleware/currentapp.js +++ b/packages/server/src/middleware/currentapp.js @@ -1,5 +1,5 @@ const { - getAppId, + getAppIdFromCtx, setCookie, getCookie, clearCookie, @@ -17,7 +17,7 @@ const { doInAppContext } = require("@budibase/backend-core/context") module.exports = async (ctx, next) => { // try to get the appID from the request - let requestAppId = getAppId(ctx) + let requestAppId = await getAppIdFromCtx(ctx) // get app cookie if it exists let appCookie = null try { @@ -71,21 +71,22 @@ module.exports = async (ctx, next) => { } return doInAppContext(appId, async () => { - let noCookieSet = false + let skipCookie = false // if the user not in the right tenant then make sure they have no permissions // need to judge this only based on the request app ID, if ( env.MULTI_TENANCY && ctx.user && requestAppId && - !isUserInAppTenant(requestAppId) + !isUserInAppTenant(requestAppId, ctx.user) ) { // don't error, simply remove the users rights (they are a public user) delete ctx.user.builder delete ctx.user.admin delete ctx.user.roles + ctx.isAuthenticated = false roleId = BUILTIN_ROLE_IDS.PUBLIC - noCookieSet = true + skipCookie = true } ctx.appId = appId @@ -105,7 +106,7 @@ module.exports = async (ctx, next) => { (requestAppId !== appId || appCookie == null || appCookie.appId !== requestAppId) && - !noCookieSet + !skipCookie ) { setCookie(ctx, { appId }, Cookies.CurrentApp) } diff --git a/packages/server/src/middleware/publicApi.js b/packages/server/src/middleware/publicApi.js index 563612c1ea..241873f5f9 100644 --- a/packages/server/src/middleware/publicApi.js +++ b/packages/server/src/middleware/publicApi.js @@ -1,9 +1,9 @@ const { Headers } = require("@budibase/backend-core/constants") -const { getAppId } = require("@budibase/backend-core/utils") +const { getAppIdFromCtx } = require("@budibase/backend-core/utils") module.exports = function ({ requiresAppId } = {}) { return async (ctx, next) => { - const appId = getAppId(ctx) + const appId = await getAppIdFromCtx(ctx) if (requiresAppId && !appId) { ctx.throw( 400, diff --git a/packages/server/src/middleware/tests/authorized.spec.js b/packages/server/src/middleware/tests/authorized.spec.js index f461a6d907..f23eb6206b 100644 --- a/packages/server/src/middleware/tests/authorized.spec.js +++ b/packages/server/src/middleware/tests/authorized.spec.js @@ -34,9 +34,7 @@ class TestConfiguration { } executeMiddleware() { - return doInAppContext(APP_ID, () => { - return this.middleware(this.ctx, this.next) - }) + return this.middleware(this.ctx, this.next) } setUser(user) { diff --git a/packages/server/src/middleware/tests/currentapp.spec.js b/packages/server/src/middleware/tests/currentapp.spec.js index 4e53a6a4c0..bee07cbf91 100644 --- a/packages/server/src/middleware/tests/currentapp.spec.js +++ b/packages/server/src/middleware/tests/currentapp.spec.js @@ -38,7 +38,7 @@ function mockAuthWithNoCookie() { }, })) jest.mock("@budibase/backend-core/utils", () => ({ - getAppId: jest.fn(), + getAppIdFromCtx: jest.fn(), setCookie: jest.fn(), getCookie: jest.fn(), })) @@ -51,7 +51,7 @@ function mockAuthWithCookie() { jest.resetModules() mockWorker() jest.mock("@budibase/backend-core/utils", () => ({ - getAppId: () => { + getAppIdFromCtx: () => { return "app_test" }, setCookie: jest.fn(), @@ -143,7 +143,7 @@ describe("Current app middleware", () => { it("should perform correct when no cookie exists", async () => { mockReset() jest.mock("@budibase/backend-core/utils", () => ({ - getAppId: () => { + getAppIdFromCtx: () => { return "app_test" }, setCookie: jest.fn(), @@ -158,7 +158,7 @@ describe("Current app middleware", () => { it("lastly check what occurs when cookie doesn't need updated", async () => { mockReset() jest.mock("@budibase/backend-core/utils", () => ({ - getAppId: () => { + getAppIdFromCtx: () => { return "app_test" }, setCookie: jest.fn(), diff --git a/packages/server/src/tests/utilities/TestConfiguration.js b/packages/server/src/tests/utilities/TestConfiguration.js index 16658bec3c..17a6fc5403 100644 --- a/packages/server/src/tests/utilities/TestConfiguration.js +++ b/packages/server/src/tests/utilities/TestConfiguration.js @@ -99,7 +99,7 @@ class TestConfiguration { return request.body } // check if already in a context - if (context.getAppId() == null) { + if (context.getAppId() == null && this.appId !== null) { return context.doInAppContext(this.appId, async () => { return run() }) diff --git a/packages/server/src/threads/query.js b/packages/server/src/threads/query.js index 3ce138b72f..270c2cc713 100644 --- a/packages/server/src/threads/query.js +++ b/packages/server/src/threads/query.js @@ -33,10 +33,12 @@ class QueryRunner { return fields } const bindings = findHBSBlocks(sql) - let variables = [] + let variables = [], + arrays = [] for (let binding of bindings) { - let variable = integration.getBindingIdentifier() - variables.push(binding) + // look for array/list operations in the SQL statement, which will need handled later + const listRegex = new RegExp(`(in|IN|In|iN)( )+${binding}`) + const listRegexMatch = sql.match(listRegex) // check if the variable was used as part of a string concat e.g. 'Hello {{binding}}' const charConstRegex = new RegExp(`'[^']*${binding}[^']*'`) const charConstMatch = sql.match(charConstRegex) @@ -46,15 +48,45 @@ class QueryRunner { part2 = `'${part2.substring(0, part2.length - 1)}'` sql = sql.replace( charConstMatch[0], - integration.getStringConcat([part1, variable, part2]) + integration.getStringConcat([ + part1, + integration.getBindingIdentifier(), + part2, + ]) + ) + } + // generate SQL parameterised array + else if (listRegexMatch) { + arrays.push(binding) + // determine the length of the array + const value = this.enrichQueryFields([binding], parameters)[0].split( + "," + ) + // build a string like ($1, $2, $3) + sql = sql.replace( + binding, + `(${Array.apply(null, Array(value.length)) + .map(() => integration.getBindingIdentifier()) + .join(",")})` ) } else { - sql = sql.replace(binding, variable) + sql = sql.replace(binding, integration.getBindingIdentifier()) } + variables.push(binding) } // replicate the knex structure fields.sql = sql fields.bindings = this.enrichQueryFields(variables, parameters) + // check for arrays in the data + let updated = [] + for (let i = 0; i < variables.length; i++) { + if (arrays.includes(variables[i])) { + updated = updated.concat(fields.bindings[i].split(",")) + } else { + updated.push(fields.bindings[i]) + } + } + fields.bindings = updated return fields } diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index 2361c5be5d..365a62105c 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -9134,9 +9134,9 @@ min-document@^2.19.0: brace-expansion "^1.1.7" minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== mixin-deep@^1.2.0: version "1.3.2" diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index dd510f59d8..d3c5427e77 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "1.0.91-alpha.17", + "version": "1.0.105-alpha.10", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/string-templates/yarn.lock b/packages/string-templates/yarn.lock index 8e01eaeb5a..ca434d6626 100644 --- a/packages/string-templates/yarn.lock +++ b/packages/string-templates/yarn.lock @@ -3145,9 +3145,9 @@ minimatch@^3.0.4: brace-expansion "^1.1.7" minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== mixin-deep@^1.2.0: version "1.3.2" diff --git a/packages/worker/.eslintrc b/packages/worker/.eslintrc deleted file mode 100644 index d94766fc59..0000000000 --- a/packages/worker/.eslintrc +++ /dev/null @@ -1,13 +0,0 @@ -{ - "globals": { - "emit": true, - "key": true - }, - "parser": "@typescript-eslint/parser", - "env": { - "node": true - }, - "extends": ["eslint:recommended"], - "rules": { - } -} diff --git a/packages/worker/.vscode/launch.json b/packages/worker/.vscode/launch.json index 7417938376..a07cf96b80 100644 --- a/packages/worker/.vscode/launch.json +++ b/packages/worker/.vscode/launch.json @@ -5,10 +5,13 @@ "version": "0.2.0", "configurations": [ { + "name": "Start Server", "type": "node", "request": "launch", - "name": "Start Server", - "program": "${workspaceFolder}/src/index.js" + "runtimeExecutable": "node", + "runtimeArgs": ["--nolazy", "-r", "ts-node/register/transpile-only"], + "args": ["src/index.ts"], + "cwd": "${workspaceRoot}", }, { "type": "node", diff --git a/packages/worker/package.json b/packages/worker/package.json index 8fe81c3626..a7c41dbfce 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "1.0.91-alpha.17", + "version": "1.0.105-alpha.10", "description": "Budibase background service", "main": "src/index.ts", "repository": { @@ -18,9 +18,6 @@ "build:docker": "docker build . -t worker-service --label version=$BUDIBASE_RELEASE_VERSION", "dev:stack:init": "node ./scripts/dev/manage.js init", "dev:builder": "npm run dev:stack:init && nodemon", - "format": "prettier --config ../../.prettierrc.json 'src/**/*.ts' --write", - "lint": "eslint --fix src/", - "lint:fix": "yarn run format && yarn run lint", "test": "jest --runInBand", "env:multi:enable": "node scripts/multiTenancy.js enable", "env:multi:disable": "node scripts/multiTenancy.js disable", @@ -34,8 +31,8 @@ "author": "Budibase", "license": "GPL-3.0", "dependencies": { - "@budibase/backend-core": "^1.0.91-alpha.17", - "@budibase/string-templates": "^1.0.91-alpha.17", + "@budibase/backend-core": "^1.0.105-alpha.10", + "@budibase/string-templates": "^1.0.105-alpha.10", "@koa/router": "^8.0.0", "@sentry/node": "6.17.7", "@techpass/passport-openidconnect": "^0.3.0", diff --git a/packages/worker/src/api/routes/tests/realEmail.spec.js b/packages/worker/src/api/routes/tests/realEmail.spec.js index c440eb13b3..6f2af0010b 100644 --- a/packages/worker/src/api/routes/tests/realEmail.spec.js +++ b/packages/worker/src/api/routes/tests/realEmail.spec.js @@ -3,6 +3,9 @@ const { EmailTemplatePurpose } = require("../../../constants") const nodemailer = require("nodemailer") const fetch = require("node-fetch") +// for the real email tests give them a long time to try complete/fail +jest.setTimeout(30000) + describe("/api/global/email", () => { beforeAll(async () => { @@ -27,6 +30,7 @@ describe("/api/global/email", () => { userId: user._id, }) .set(config.defaultHeaders()) + .timeout(20000) // ethereal hiccup, can't test right now if (res.status >= 300) { return @@ -39,7 +43,7 @@ describe("/api/global/email", () => { text = await response.text() } catch (err) { // ethereal hiccup, can't test right now - if (parseInt(err.status) >= 300) { + if (parseInt(err.status) >= 300 || (err && err.errno === "ETIME")) { return } else { throw err diff --git a/packages/worker/src/environment.js b/packages/worker/src/environment.js index 91f06ea46d..c965863a54 100644 --- a/packages/worker/src/environment.js +++ b/packages/worker/src/environment.js @@ -19,7 +19,7 @@ if (!LOADED && isDev() && !isTest()) { module.exports = { NODE_ENV: process.env.NODE_ENV, SELF_HOSTED: !!parseInt(process.env.SELF_HOSTED), - PORT: process.env.PORT, + PORT: process.env.PORT || process.env.WORKER_PORT, CLUSTER_PORT: process.env.CLUSTER_PORT, MINIO_ACCESS_KEY: process.env.MINIO_ACCESS_KEY, MINIO_SECRET_KEY: process.env.MINIO_SECRET_KEY, diff --git a/packages/worker/yarn.lock b/packages/worker/yarn.lock index f163f6df59..f85b640c0f 100644 --- a/packages/worker/yarn.lock +++ b/packages/worker/yarn.lock @@ -286,67 +286,6 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@^1.0.91-alpha.17": - version "1.0.111" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-1.0.111.tgz#7af3cc89792e99ee8ce2e4c7ed4a19355db64a10" - integrity sha512-vVE6pH1BYnxt4Z+KHEfPDEaHFZPoZafE8c5Ij2Zr1y7Yk1psY1PtzWat4831624/UrdqEPpEJ+PWFleyfLVdXw== - dependencies: - "@techpass/passport-openidconnect" "^0.3.0" - aws-sdk "^2.901.0" - bcryptjs "^2.4.3" - cls-hooked "^4.2.2" - ioredis "^4.27.1" - jsonwebtoken "^8.5.1" - koa-passport "^4.1.4" - lodash "^4.17.21" - lodash.isarguments "^3.1.0" - node-fetch "^2.6.1" - passport-google-auth "^1.0.2" - passport-google-oauth "^2.0.0" - passport-jwt "^4.0.0" - passport-local "^1.0.0" - sanitize-s3-objectkey "^0.0.1" - tar-fs "^2.1.1" - uuid "^8.3.2" - zlib "^1.0.5" - -"@budibase/handlebars-helpers@^0.11.8": - version "0.11.8" - resolved "https://registry.yarnpkg.com/@budibase/handlebars-helpers/-/handlebars-helpers-0.11.8.tgz#6953d29673a8c5c407e096c0a84890465c7ce841" - integrity sha512-ggWJUt0GqsHFAEup5tlWlcrmYML57nKhpNGGLzVsqXVYN8eVmf3xluYmmMe7fDYhQH0leSprrdEXmsdFQF3HAQ== - dependencies: - array-sort "^1.0.0" - define-property "^2.0.2" - extend-shallow "^3.0.2" - for-in "^1.0.2" - get-object "^0.2.0" - get-value "^3.0.1" - handlebars "^4.7.7" - handlebars-utils "^1.0.6" - has-value "^2.0.2" - helper-md "^0.2.2" - html-tag "^2.0.0" - is-even "^1.0.0" - is-glob "^4.0.1" - kind-of "^6.0.3" - micromatch "^3.1.5" - relative "^3.0.2" - striptags "^3.1.1" - to-gfm-code-block "^0.1.1" - year "^0.2.1" - -"@budibase/string-templates@^1.0.91-alpha.17": - version "1.0.111" - resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-1.0.111.tgz#34915e38351cd77b3ef238b845fc46eda40f310c" - integrity sha512-cyfSI0ksNw/EUT/pTHxyUunPfNl1SW/yTZvvb+AOecaHC/h/dY6VJCdJCYMt7CW/q4dK2dTI65AAxrJFGqLriw== - dependencies: - "@budibase/handlebars-helpers" "^0.11.8" - dayjs "^1.10.4" - handlebars "^4.7.6" - handlebars-utils "^1.0.6" - lodash "^4.17.20" - vm2 "^3.9.4" - "@cspotcode/source-map-consumer@0.8.0": version "0.8.0" resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b" @@ -1151,7 +1090,7 @@ acorn-walk@^7.1.1: resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== -acorn-walk@^8.1.1, acorn-walk@^8.2.0: +acorn-walk@^8.1.1: version "8.2.0" resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== @@ -1166,7 +1105,7 @@ acorn@^7.1.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^8.2.4, acorn@^8.4.1, acorn@^8.7.0: +acorn@^8.2.4, acorn@^8.4.1: version "8.7.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== @@ -1208,9 +1147,9 @@ ansi-escapes@^4.2.1: type-fest "^0.21.3" ansi-regex@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" - integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" + integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== ansi-regex@^5.0.0, ansi-regex@^5.0.1: version "5.0.1" @@ -1249,7 +1188,7 @@ arg@^4.1.0: resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== -argparse@^1.0.10, argparse@^1.0.7: +argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== @@ -1271,40 +1210,11 @@ argsarray@0.0.1: resolved "https://registry.yarnpkg.com/argsarray/-/argsarray-0.0.1.tgz#6e7207b4ecdb39b0af88303fa5ae22bda8df61cb" integrity sha1-bnIHtOzbObCviDA/pa4ivajfYcs= -arr-diff@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" - integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= - -arr-flatten@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" - integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== - -arr-union@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" - integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= - -array-sort@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-sort/-/array-sort-1.0.0.tgz#e4c05356453f56f53512a7d1d6123f2c54c0a88a" - integrity sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg== - dependencies: - default-compare "^1.0.0" - get-value "^2.0.6" - kind-of "^5.0.2" - array-union@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -array-unique@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" - integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= - asap@^2.0.0: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" @@ -1322,11 +1232,6 @@ assert-plus@1.0.0, assert-plus@^1.0.0: resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= -assign-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" - integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= - ast-types@0.9.6: version "0.9.6" resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9" @@ -1337,42 +1242,16 @@ astral-regex@^1.0.0: resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== -async-hook-jl@^1.7.6: - version "1.7.6" - resolved "https://registry.yarnpkg.com/async-hook-jl/-/async-hook-jl-1.7.6.tgz#4fd25c2f864dbaf279c610d73bf97b1b28595e68" - integrity sha512-gFaHkFfSxTjvoxDMYqDuGHlcRyUuamF8s+ZTtJdDzqjws4mCt7v0vuV79/E2Wr2/riMQgtG4/yUtXWs1gZ7JMg== - dependencies: - stack-chain "^1.3.7" - -async@~2.1.4: - version "2.1.5" - resolved "https://registry.yarnpkg.com/async/-/async-2.1.5.tgz#e587c68580994ac67fc56ff86d3ac56bdbe810bc" - integrity sha1-5YfGhYCZSsZ/xW/4bTrFa9voELw= - dependencies: - lodash "^4.14.0" - asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= -atob@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" - integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== - atomic-sleep@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b" integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== -autolinker@~0.28.0: - version "0.28.1" - resolved "https://registry.yarnpkg.com/autolinker/-/autolinker-0.28.1.tgz#0652b491881879f0775dace0cdca3233942a4e47" - integrity sha1-BlK0kYgYefB3XazgzcoyM5QqTkc= - dependencies: - gulp-header "^1.7.1" - aws-sdk@^2.811.0: version "2.1066.0" resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1066.0.tgz#2a9b00d983f3c740a7adda18d4e9a5c34d4d3887" @@ -1388,21 +1267,6 @@ aws-sdk@^2.811.0: uuid "3.3.2" xml2js "0.4.19" -aws-sdk@^2.901.0: - version "2.1111.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1111.0.tgz#02b1e5c530ef8140235ee7c48c710bb2dbd7dc84" - integrity sha512-WRyNcCckzmu1djTAWfR2r+BuI/PbuLrhG3oa+oH39v4NZ4EecYWFL1CoCPlC2kRUML4maSba5T4zlxjcNl7ELQ== - dependencies: - buffer "4.9.2" - events "1.1.1" - ieee754 "1.1.13" - jmespath "0.16.0" - querystring "0.2.0" - sax "1.2.1" - url "0.10.3" - uuid "3.3.2" - xml2js "0.4.19" - aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" @@ -1494,19 +1358,6 @@ base64url@3.x.x, base64url@^3.0.1: resolved "https://registry.yarnpkg.com/base64url/-/base64url-3.0.1.tgz#6399d572e2bc3f90a9a8b22d5dbb0a32d33f788d" integrity sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A== -base@^0.11.1: - version "0.11.2" - resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" - integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== - dependencies: - cache-base "^1.0.1" - class-utils "^0.3.5" - component-emitter "^1.2.1" - define-property "^1.0.0" - isobject "^3.0.1" - mixin-deep "^1.2.0" - pascalcase "^0.1.1" - bcrypt-pbkdf@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" @@ -1524,15 +1375,6 @@ binary-extensions@^2.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== -bl@^4.0.3: - version "4.1.0" - resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" - integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== - dependencies: - buffer "^5.5.0" - inherits "^2.0.4" - readable-stream "^3.4.0" - boxen@^5.0.0: version "5.1.2" resolved "https://registry.yarnpkg.com/boxen/-/boxen-5.1.2.tgz#788cb686fc83c1f486dfa8a40c68fc2b831d2b50" @@ -1555,22 +1397,6 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" -braces@^2.3.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" - integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== - dependencies: - arr-flatten "^1.1.0" - array-unique "^0.3.2" - extend-shallow "^2.0.1" - fill-range "^4.0.0" - isobject "^3.0.1" - repeat-element "^1.1.2" - snapdragon "^0.8.1" - snapdragon-node "^2.0.1" - split-string "^3.0.2" - to-regex "^3.0.1" - braces@^3.0.1, braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" @@ -1650,21 +1476,6 @@ bytes@^3.0.0: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== -cache-base@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" - integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== - dependencies: - collection-visit "^1.0.0" - component-emitter "^1.2.1" - get-value "^2.0.6" - has-value "^1.0.0" - isobject "^3.0.1" - set-value "^2.0.0" - to-object-path "^0.3.0" - union-value "^1.0.0" - unset-value "^1.0.0" - cache-content-type@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/cache-content-type/-/cache-content-type-1.0.1.tgz#035cde2b08ee2129f4a8315ea8f00a00dba1453c" @@ -1784,11 +1595,6 @@ chokidar@^3.5.2: optionalDependencies: fsevents "~2.3.2" -chownr@^1.1.1: - version "1.1.4" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" - integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== - ci-info@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" @@ -1804,16 +1610,6 @@ cjs-module-lexer@^1.0.0: resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== -class-utils@^0.3.5: - version "0.3.6" - resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" - integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== - dependencies: - arr-union "^3.1.0" - define-property "^0.2.5" - isobject "^3.0.0" - static-extend "^0.1.1" - cli-boxes@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" @@ -1852,20 +1648,6 @@ clone-response@^1.0.2: dependencies: mimic-response "^1.0.0" -cls-hooked@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/cls-hooked/-/cls-hooked-4.2.2.tgz#ad2e9a4092680cdaffeb2d3551da0e225eae1908" - integrity sha512-J4Xj5f5wq/4jAvcdgoGsL3G103BtWpZrMo8NEinRltN+xpTZdI+M38pyQqhuFU/P792xkMFvnKSf+Lm81U1bxw== - dependencies: - async-hook-jl "^1.7.6" - emitter-listener "^1.0.1" - semver "^5.4.1" - -cluster-key-slot@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d" - integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw== - co-body@^5.1.1: version "5.2.0" resolved "https://registry.yarnpkg.com/co-body/-/co-body-5.2.0.tgz#5a0a658c46029131e0e3a306f67647302f71c124" @@ -1886,14 +1668,6 @@ collect-v8-coverage@^1.0.0: resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== -collection-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" - integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= - dependencies: - map-visit "^1.0.0" - object-visit "^1.0.0" - color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -1945,7 +1719,7 @@ commoner@^0.10.1: q "^1.1.2" recast "^0.11.17" -component-emitter@^1.2.1, component-emitter@^1.3.0: +component-emitter@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== @@ -1962,13 +1736,6 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -concat-with-sourcemaps@*: - version "1.1.0" - resolved "https://registry.yarnpkg.com/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz#d4ea93f05ae25790951b99e7b3b09e3908a4082e" - integrity sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg== - dependencies: - source-map "^0.6.1" - configstore@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96" @@ -2018,11 +1785,6 @@ cookies@~0.8.0: depd "~2.0.0" keygrip "~1.1.0" -copy-descriptor@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" - integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= - copyfiles@^2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/copyfiles/-/copyfiles-2.4.1.tgz#d2dcff60aaad1015f09d0b66e7f0f1c5cd3c5da5" @@ -2121,11 +1883,6 @@ dateformat@^4.5.1: resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-4.6.3.tgz#556fa6497e5217fedb78821424f8a1c22fa3f4b5" integrity sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA== -dayjs@^1.10.4: - version "1.11.0" - resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.0.tgz#009bf7ef2e2ea2d5db2e6583d2d39a4b5061e805" - integrity sha512-JLC809s6Y948/FuCZPm5IX8rRhQwOiyMb2TfVVQEixG7P8Lm/gt5S7yoQZmC8x1UehI9Pb7sksEt4xx14m+7Ug== - debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.3: version "4.3.3" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" @@ -2133,13 +1890,6 @@ debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.3: dependencies: ms "2.1.2" -debug@^2.2.0, debug@^2.3.3: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - debug@^3.1.0, debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -2147,23 +1897,11 @@ debug@^3.1.0, debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.3.1: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - decimal.js@^10.2.1: version "10.3.1" resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ== -decode-uri-component@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" - integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= - decompress-response@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" @@ -2203,13 +1941,6 @@ deepmerge@^4.2.2: resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== -default-compare@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/default-compare/-/default-compare-1.0.0.tgz#cb61131844ad84d84788fb68fd01681ca7781a2f" - integrity sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ== - dependencies: - kind-of "^5.0.2" - defer-to-connect@^1.0.1: version "1.1.3" resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" @@ -2228,28 +1959,6 @@ deferred-leveldown@~5.3.0: abstract-leveldown "~6.2.1" inherits "^2.0.3" -define-property@^0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" - integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= - dependencies: - is-descriptor "^0.1.0" - -define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" - integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= - dependencies: - is-descriptor "^1.0.0" - -define-property@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" - integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== - dependencies: - is-descriptor "^1.0.2" - isobject "^3.0.1" - defined@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" @@ -2265,11 +1974,6 @@ delegates@^1.0.0: resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= -denque@^1.1.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.1.tgz#07f670e29c9a78f8faecb2566a1e2c11929c5cbf" - integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw== - depd@^2.0.0, depd@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" @@ -2389,13 +2093,6 @@ electron-to-chromium@^1.4.17: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.58.tgz#cd980b08338210b591c25492857a518fe286b1d4" integrity sha512-7LXwnKyqcEaMFVXOer+2JPfFs1D+ej7yRRrfZoIH1YlLQZ81OvBNwSCBBLtExVkoMQQgOWwO0FbZVge6U/8rhQ== -emitter-listener@^1.0.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/emitter-listener/-/emitter-listener-1.1.2.tgz#56b140e8f6992375b3d7cb2cab1cc7432d9632e8" - integrity sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ== - dependencies: - shimmer "^1.2.0" - emittery@^0.8.1: version "0.8.1" resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860" @@ -2426,7 +2123,7 @@ encoding-down@^6.3.0: level-codec "^9.0.0" level-errors "^2.0.0" -end-of-stream@^1.1.0, end-of-stream@^1.4.1: +end-of-stream@^1.1.0: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== @@ -2440,11 +2137,6 @@ end-stream@~0.1.0: dependencies: write-stream "~0.4.3" -ent@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d" - integrity sha1-6WQhkyWiHQX0RGai9obtbOX13R0= - errno@~0.1.1: version "0.1.8" resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" @@ -2654,19 +2346,6 @@ exit@^0.1.2: resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= -expand-brackets@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" - integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= - dependencies: - debug "^2.3.3" - define-property "^0.2.5" - extend-shallow "^2.0.1" - posix-character-classes "^0.1.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - expect@^27.4.6: version "27.4.6" resolved "https://registry.yarnpkg.com/expect/-/expect-27.4.6.tgz#f335e128b0335b6ceb4fcab67ece7cbd14c942e6" @@ -2677,21 +2356,6 @@ expect@^27.4.6: jest-matcher-utils "^27.4.6" jest-message-util "^27.4.6" -extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= - dependencies: - is-extendable "^0.1.0" - -extend-shallow@^3.0.0, extend-shallow@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" - integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= - dependencies: - assign-symbols "^1.0.0" - is-extendable "^1.0.1" - extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" @@ -2706,20 +2370,6 @@ external-editor@^3.0.3: iconv-lite "^0.4.24" tmp "^0.0.33" -extglob@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" - integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== - dependencies: - array-unique "^0.3.2" - define-property "^1.0.0" - expand-brackets "^2.1.4" - extend-shallow "^2.0.1" - fragment-cache "^0.2.1" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - extsprintf@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" @@ -2808,16 +2458,6 @@ file-entry-cache@^5.0.1: dependencies: flat-cache "^2.0.1" -fill-range@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" - integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= - dependencies: - extend-shallow "^2.0.1" - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range "^2.1.0" - fill-range@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" @@ -2852,11 +2492,6 @@ flatted@^2.0.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== -for-in@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= - forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" @@ -2904,28 +2539,11 @@ formidable@^2.0.1: once "1.4.0" qs "6.9.3" -fragment-cache@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" - integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= - dependencies: - map-cache "^0.2.2" - fresh@~0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= -fs-constants@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" - integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== - -fs-exists-sync@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" - integrity sha1-mC1ok6+RjnLQjeyehnP/K1qNat0= - fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -2965,14 +2583,6 @@ get-intrinsic@^1.0.2: has "^1.0.3" has-symbols "^1.0.1" -get-object@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/get-object/-/get-object-0.2.0.tgz#d92ff7d5190c64530cda0543dac63a3d47fe8c0c" - integrity sha1-2S/31RkMZFMM2gVD2sY6PUf+jAw= - dependencies: - is-number "^2.0.2" - isobject "^0.2.0" - get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" @@ -2997,18 +2607,6 @@ get-stream@^6.0.0: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== -get-value@^2.0.3, get-value@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= - -get-value@^3.0.0, get-value@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/get-value/-/get-value-3.0.1.tgz#5efd2a157f1d6a516d7524e124ac52d0a39ef5a8" - integrity sha512-mKZj9JLQrwMBtj5wxi6MH8Z5eSKaERpAwjg43dPtlGI1ZVEgH/qC7T8/6R2OBSUA+zzHBZgICsVJaEIV2tKTDA== - dependencies: - isobject "^3.0.1" - getpass@^0.1.1: version "0.1.7" resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" @@ -3077,32 +2675,6 @@ globby@^11.0.4: merge2 "^1.4.1" slash "^3.0.0" -google-auth-library@~0.10.0: - version "0.10.0" - resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-0.10.0.tgz#6e15babee85fd1dd14d8d128a295b6838d52136e" - integrity sha1-bhW6vuhf0d0U2NEoopW2g41SE24= - dependencies: - gtoken "^1.2.1" - jws "^3.1.4" - lodash.noop "^3.0.1" - request "^2.74.0" - -google-p12-pem@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/google-p12-pem/-/google-p12-pem-0.1.2.tgz#33c46ab021aa734fa0332b3960a9a3ffcb2f3177" - integrity sha1-M8RqsCGqc0+gMys5YKmj/8svMXc= - dependencies: - node-forge "^0.7.1" - -googleapis@^16.0.0: - version "16.1.0" - resolved "https://registry.yarnpkg.com/googleapis/-/googleapis-16.1.0.tgz#0f19f2d70572d918881a0f626e3b1a2fa8629576" - integrity sha1-Dxny1wVy2RiIGg9ibjsaL6hilXY= - dependencies: - async "~2.1.4" - google-auth-library "~0.10.0" - string-template "~1.0.0" - got@^11.8.1: version "11.8.3" resolved "https://registry.yarnpkg.com/got/-/got-11.8.3.tgz#f496c8fdda5d729a90b4905d2b07dbd148170770" @@ -3142,45 +2714,6 @@ graceful-fs@^4.1.2, graceful-fs@^4.2.4: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== -gtoken@^1.2.1: - version "1.2.3" - resolved "https://registry.yarnpkg.com/gtoken/-/gtoken-1.2.3.tgz#5509571b8afd4322e124cf66cf68115284c476d8" - integrity sha512-wQAJflfoqSgMWrSBk9Fg86q+sd6s7y6uJhIvvIPz++RElGlMtEqsdAR2oWwZ/WTEtp7P9xFbJRrT976oRgzJ/w== - dependencies: - google-p12-pem "^0.1.0" - jws "^3.0.0" - mime "^1.4.1" - request "^2.72.0" - -gulp-header@^1.7.1: - version "1.8.12" - resolved "https://registry.yarnpkg.com/gulp-header/-/gulp-header-1.8.12.tgz#ad306be0066599127281c4f8786660e705080a84" - integrity sha512-lh9HLdb53sC7XIZOYzTXM4lFuXElv3EVkSDhsd7DoJBj7hm+Ni7D3qYbb+Rr8DuM8nRanBvkVO9d7askreXGnQ== - dependencies: - concat-with-sourcemaps "*" - lodash.template "^4.4.0" - through2 "^2.0.0" - -handlebars-utils@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/handlebars-utils/-/handlebars-utils-1.0.6.tgz#cb9db43362479054782d86ffe10f47abc76357f9" - integrity sha512-d5mmoQXdeEqSKMtQQZ9WkiUcO1E3tPbWxluCK9hVgIDPzQa9WsKo3Lbe/sGflTe7TomHEeZaOgwIkyIr1kfzkw== - dependencies: - kind-of "^6.0.0" - typeof-article "^0.1.1" - -handlebars@^4.7.6, handlebars@^4.7.7: - version "4.7.7" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" - integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA== - dependencies: - minimist "^1.2.5" - neo-async "^2.6.0" - source-map "^0.6.1" - wordwrap "^1.0.0" - optionalDependencies: - uglify-js "^3.1.4" - har-schema@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" @@ -3216,52 +2749,6 @@ has-tostringtag@^1.0.0: dependencies: has-symbols "^1.0.2" -has-value@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" - integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= - dependencies: - get-value "^2.0.3" - has-values "^0.1.4" - isobject "^2.0.0" - -has-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" - integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= - dependencies: - get-value "^2.0.6" - has-values "^1.0.0" - isobject "^3.0.0" - -has-value@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-2.0.2.tgz#d0f12e8780ba8e90e66ad1a21c707fdb67c25658" - integrity sha512-ybKOlcRsK2MqrM3Hmz/lQxXHZ6ejzSPzpNabKB45jb5qDgJvKPa3SdapTsTLwEb9WltgWpOmNax7i+DzNOk4TA== - dependencies: - get-value "^3.0.0" - has-values "^2.0.1" - -has-values@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" - integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= - -has-values@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" - integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - -has-values@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-2.0.1.tgz#3876200ff86d8a8546a9264a952c17d5fc17579d" - integrity sha512-+QdH3jOmq9P8GfdjFg0eJudqx1FqU62NQJ4P16rOEHeRdl7ckgwn6uqQjzYE0ZoHVV/e5E2esuJ5Gl5+HUW19w== - dependencies: - kind-of "^6.0.2" - has-yarn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77" @@ -3274,16 +2761,6 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" -helper-md@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/helper-md/-/helper-md-0.2.2.tgz#c1f59d7e55bbae23362fd8a0e971607aec69d41f" - integrity sha1-wfWdflW7riM2L9ig6XFgeuxp1B8= - dependencies: - ent "^2.2.0" - extend-shallow "^2.0.1" - fs-exists-sync "^0.1.0" - remarkable "^1.6.2" - hexoid@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/hexoid/-/hexoid-1.0.0.tgz#ad10c6573fb907de23d9ec63a711267d9dc9bc18" @@ -3301,14 +2778,6 @@ html-escaper@^2.0.0: resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== -html-tag@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/html-tag/-/html-tag-2.0.0.tgz#36c3bc8d816fd30b570d5764a497a641640c2fed" - integrity sha512-XxzooSo6oBoxBEUazgjdXj7VwTn/iSTSZzTYKzYY6I916tkaYzypHxy+pbVU1h+0UQ9JlVf5XkNQyxOAiiQO1g== - dependencies: - is-self-closing "^1.0.1" - kind-of "^6.0.0" - http-assert@^1.3.0: version "1.5.0" resolved "https://registry.yarnpkg.com/http-assert/-/http-assert-1.5.0.tgz#c389ccd87ac16ed2dfa6246fd73b926aa00e6b8f" @@ -3502,37 +2971,6 @@ inquirer@^7.0.0: strip-ansi "^6.0.0" through "^2.3.6" -ioredis@^4.27.1: - version "4.28.5" - resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.28.5.tgz#5c149e6a8d76a7f8fa8a504ffc85b7d5b6797f9f" - integrity sha512-3GYo0GJtLqgNXj4YhrisLaNNvWSNwSS2wS4OELGfGxH8I69+XfNdnmV1AyN+ZqMh0i7eX+SWjrwFKDBDgfBC1A== - dependencies: - cluster-key-slot "^1.1.0" - debug "^4.3.1" - denque "^1.1.0" - lodash.defaults "^4.2.0" - lodash.flatten "^4.4.0" - lodash.isarguments "^3.1.0" - p-map "^2.1.0" - redis-commands "1.7.0" - redis-errors "^1.2.0" - redis-parser "^3.0.0" - standard-as-callback "^2.1.0" - -is-accessor-descriptor@^0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" - integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= - dependencies: - kind-of "^3.0.2" - -is-accessor-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" - integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== - dependencies: - kind-of "^6.0.0" - is-binary-path@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" @@ -3540,11 +2978,6 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" -is-buffer@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== - is-ci@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" @@ -3564,57 +2997,6 @@ is-core-module@^2.8.1: dependencies: has "^1.0.3" -is-data-descriptor@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" - integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= - dependencies: - kind-of "^3.0.2" - -is-data-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" - integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== - dependencies: - kind-of "^6.0.0" - -is-descriptor@^0.1.0: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" - integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== - dependencies: - is-accessor-descriptor "^0.1.6" - is-data-descriptor "^0.1.4" - kind-of "^5.0.0" - -is-descriptor@^1.0.0, is-descriptor@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" - integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== - dependencies: - is-accessor-descriptor "^1.0.0" - is-data-descriptor "^1.0.0" - kind-of "^6.0.2" - -is-even@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-even/-/is-even-1.0.0.tgz#76b5055fbad8d294a86b6a949015e1c97b717c06" - integrity sha1-drUFX7rY0pSoa2qUkBXhyXtxfAY= - dependencies: - is-odd "^0.1.2" - -is-extendable@^0.1.0, is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= - -is-extendable@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" - integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== - dependencies: - is-plain-object "^2.0.4" - is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" @@ -3662,20 +3044,6 @@ is-npm@^5.0.0: resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-5.0.0.tgz#43e8d65cc56e1b67f8d47262cf667099193f45a8" integrity sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA== -is-number@^2.0.2: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" - integrity sha1-Afy7s5NGOlSPL0ZszhbezknbkI8= - dependencies: - kind-of "^3.0.2" - -is-number@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= - dependencies: - kind-of "^3.0.2" - is-number@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" @@ -3686,37 +3054,16 @@ is-obj@^2.0.0: resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== -is-odd@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/is-odd/-/is-odd-0.1.2.tgz#bc573b5ce371ef2aad6e6f49799b72bef13978a7" - integrity sha1-vFc7XONx7yqtbm9JeZtyvvE5eKc= - dependencies: - is-number "^3.0.0" - is-path-inside@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== -is-plain-object@^2.0.3, is-plain-object@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" - integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== - dependencies: - isobject "^3.0.1" - is-potential-custom-element-name@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== -is-self-closing@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-self-closing/-/is-self-closing-1.0.1.tgz#5f406b527c7b12610176320338af0fa3896416e4" - integrity sha512-E+60FomW7Blv5GXTlYee2KDrnG6srxF7Xt1SjrhWUGUEsTFIqY/nq2y3DaftCsgUMdh89V07IVfhY9KIJhLezg== - dependencies: - self-closing-tags "^1.0.1" - is-stream@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" @@ -3736,11 +3083,6 @@ is-typedarray@^1.0.0, is-typedarray@~1.0.0: resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= -is-windows@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" - integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== - is-yarn-global@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232" @@ -3751,7 +3093,7 @@ isarray@0.0.1: resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= -isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: +isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= @@ -3761,23 +3103,6 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= -isobject@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-0.2.0.tgz#a3432192f39b910b5f02cc989487836ec70aa85e" - integrity sha1-o0MhkvObkQtfAsyYlIeDbscKqF4= - -isobject@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= - dependencies: - isarray "1.0.0" - -isobject@^3.0.0, isobject@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= - isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" @@ -4363,7 +3688,7 @@ json5@2.x, json5@^2.1.2: dependencies: minimist "^1.2.5" -jsonwebtoken@^8.2.0, jsonwebtoken@^8.5.1: +jsonwebtoken@^8.2.0: version "8.5.1" resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w== @@ -4409,7 +3734,7 @@ jwa@^1.4.1: ecdsa-sig-formatter "1.0.11" safe-buffer "^5.0.1" -jws@^3.0.0, jws@^3.1.4, jws@^3.2.2: +jws@^3.2.2: version "3.2.2" resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== @@ -4438,30 +3763,6 @@ keyv@^4.0.0: dependencies: json-buffer "3.0.1" -kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.1.0, kind-of@^3.2.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= - dependencies: - is-buffer "^1.1.5" - -kind-of@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= - dependencies: - is-buffer "^1.1.5" - -kind-of@^5.0.0, kind-of@^5.0.2: - version "5.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" - integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== - -kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" - integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== - kleur@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" @@ -4703,31 +4004,11 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" -lodash._reinterpolate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" - integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= - -lodash.defaults@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" - integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw= - -lodash.flatten@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" - integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= - lodash.includes@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" integrity sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8= -lodash.isarguments@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" - integrity sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo= - lodash.isboolean@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" @@ -4758,32 +4039,12 @@ lodash.memoize@4.x: resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= -lodash.noop@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash.noop/-/lodash.noop-3.0.1.tgz#38188f4d650a3a474258439b96ec45b32617133c" - integrity sha1-OBiPTWUKOkdCWEObluxFsyYXEzw= - lodash.once@^4.0.0: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= -lodash.template@^4.4.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" - integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A== - dependencies: - lodash._reinterpolate "^3.0.0" - lodash.templatesettings "^4.0.0" - -lodash.templatesettings@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33" - integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ== - dependencies: - lodash._reinterpolate "^3.0.0" - -lodash@^4.14.0, lodash@^4.17.14, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0: +lodash@^4.17.14, lodash@^4.17.19, lodash@^4.7.0: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -4834,18 +4095,6 @@ makeerror@1.0.12: dependencies: tmpl "1.0.5" -map-cache@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= - -map-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" - integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= - dependencies: - object-visit "^1.0.0" - media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" @@ -4878,25 +4127,6 @@ methods@^1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= -micromatch@^3.1.5: - version "3.1.10" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" - integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - braces "^2.3.1" - define-property "^2.0.2" - extend-shallow "^3.0.2" - extglob "^2.0.4" - fragment-cache "^0.2.1" - kind-of "^6.0.2" - nanomatch "^1.2.9" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.2" - micromatch@^4.0.4: version "4.0.4" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" @@ -4917,11 +4147,6 @@ mime-types@^2.1.12, mime-types@^2.1.18, mime-types@~2.1.19, mime-types@~2.1.24: dependencies: mime-db "1.51.0" -mime@^1.4.1: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== - mime@^2.5.0: version "2.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" @@ -4950,22 +4175,9 @@ mimic-response@^3.1.0: brace-expansion "^1.1.7" minimist@^1.2.0, minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== - -mixin-deep@^1.2.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" - integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== - dependencies: - for-in "^1.0.2" - is-extendable "^1.0.1" - -mkdirp-classic@^0.5.2: - version "0.5.3" - resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" - integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== mkdirp@^0.5.0, mkdirp@^0.5.1: version "0.5.5" @@ -4984,11 +4196,6 @@ mri@1.1.4: resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.4.tgz#7cb1dd1b9b40905f1fac053abe25b6720f44744a" integrity sha512-6y7IjGPm8AzlvoUrwAaw1tLnUBudaS3752vcd8JtrpGGQn+rXIe63LFVHm/YMwtqAuh+LJPCFdlLYPWM1nYn6w== -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" @@ -5004,23 +4211,6 @@ mute-stream@0.0.8: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== -nanomatch@^1.2.9: - version "1.2.13" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" - integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - define-property "^2.0.2" - extend-shallow "^3.0.2" - fragment-cache "^0.2.1" - is-windows "^1.0.2" - kind-of "^6.0.2" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - napi-macros@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/napi-macros/-/napi-macros-2.0.0.tgz#2b6bae421e7b96eb687aa6c77a7858640670001b" @@ -5036,11 +4226,6 @@ negotiator@0.6.2: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== -neo-async@^2.6.0: - version "2.6.2" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" - integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== - nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" @@ -5058,11 +4243,6 @@ node-fetch@^2.6.1: dependencies: whatwg-url "^5.0.0" -node-forge@^0.7.1: - version "0.7.6" - resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.6.tgz#fdf3b418aee1f94f0ef642cd63486c77ca9724ac" - integrity sha512-sol30LUpz1jQFBjOKwbjxijiE3b6pjd74YwfD0fJOKPjF+fONKb2Yg8rYgS6+bK6VDl+/wfr4IYpC7jDzLUIfw== - node-gyp-build@~4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.1.1.tgz#d7270b5d86717068d114cc57fff352f96d745feb" @@ -5156,34 +4336,11 @@ object-assign@^2.0.0: resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-2.1.1.tgz#43c36e5d569ff8e4816c4efa8be02d26967c18aa" integrity sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo= -object-copy@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" - integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= - dependencies: - copy-descriptor "^0.1.0" - define-property "^0.2.5" - kind-of "^3.0.3" - object-inspect@^1.9.0: version "1.12.0" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0" integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g== -object-visit@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" - integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= - dependencies: - isobject "^3.0.0" - -object.pick@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" - integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= - dependencies: - isobject "^3.0.1" - on-finished@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" @@ -5251,11 +4408,6 @@ p-locate@^4.1.0: dependencies: p-limit "^2.2.0" -p-map@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" - integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== - p-try@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" @@ -5288,19 +4440,6 @@ parseurl@^1.3.2: resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== -pascalcase@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" - integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= - -passport-google-auth@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/passport-google-auth/-/passport-google-auth-1.0.2.tgz#8b300b5aa442ef433de1d832ed3112877d0b2938" - integrity sha1-izALWqRC70M94dgy7TESh30LKTg= - dependencies: - googleapis "^16.0.0" - passport-strategy "1.x" - passport-google-oauth1@1.x.x: version "1.0.0" resolved "https://registry.yarnpkg.com/passport-google-oauth1/-/passport-google-oauth1-1.0.0.tgz#af74a803df51ec646f66a44d82282be6f108e0cc" @@ -5358,7 +4497,7 @@ passport-oauth2@1.x.x: uid2 "0.0.x" utils-merge "1.x.x" -passport-strategy@1.x, passport-strategy@1.x.x, passport-strategy@^1.0.0: +passport-strategy@1.x.x, passport-strategy@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4" integrity sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ= @@ -5490,11 +4629,6 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" -posix-character-classes@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" - integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= - pouchdb-adapter-leveldb-core@7.2.2: version "7.2.2" resolved "https://registry.yarnpkg.com/pouchdb-adapter-leveldb-core/-/pouchdb-adapter-leveldb-core-7.2.2.tgz#e0aa6a476e2607d7ae89f4a803c9fba6e6d05a8a" @@ -5817,7 +4951,7 @@ readable-stream@1.1.14: isarray "0.0.1" string_decoder "~0.10.x" -"readable-stream@2 || 3", readable-stream@^3.0.0, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: +"readable-stream@2 || 3", readable-stream@^3.0.0, readable-stream@^3.4.0, readable-stream@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== @@ -5871,31 +5005,6 @@ recast@^0.11.17: private "~0.1.5" source-map "~0.5.0" -redis-commands@1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.7.0.tgz#15a6fea2d58281e27b1cd1acfb4b293e278c3a89" - integrity sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ== - -redis-errors@^1.0.0, redis-errors@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" - integrity sha1-62LSrbFeTq9GEMBK/hUpOEJQq60= - -redis-parser@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" - integrity sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ= - dependencies: - redis-errors "^1.0.0" - -regex-not@^1.0.0, regex-not@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" - integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== - dependencies: - extend-shallow "^3.0.2" - safe-regex "^1.1.0" - regexpp@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" @@ -5915,32 +5024,7 @@ registry-url@^5.0.0: dependencies: rc "^1.2.8" -relative@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/relative/-/relative-3.0.2.tgz#0dcd8ec54a5d35a3c15e104503d65375b5a5367f" - integrity sha1-Dc2OxUpdNaPBXhBFA9ZTdbWlNn8= - dependencies: - isobject "^2.0.0" - -remarkable@^1.6.2: - version "1.7.4" - resolved "https://registry.yarnpkg.com/remarkable/-/remarkable-1.7.4.tgz#19073cb960398c87a7d6546eaa5e50d2022fcd00" - integrity sha512-e6NKUXgX95whv7IgddywbeN/ItCkWbISmc2DiqHJb0wTrqZIexqdco5b8Z3XZoo/48IdNVKM9ZCvTPJ4F5uvhg== - dependencies: - argparse "^1.0.10" - autolinker "~0.28.0" - -repeat-element@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" - integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== - -repeat-string@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= - -request@^2.72.0, request@^2.74.0, request@^2.88.0: +request@^2.88.0: version "2.88.2" resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== @@ -6001,11 +5085,6 @@ resolve-path@^1.4.0: http-errors "~1.6.2" path-is-absolute "1.0.1" -resolve-url@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" - integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= - resolve.exports@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9" @@ -6042,11 +5121,6 @@ restore-cursor@^3.1.0: onetime "^5.1.0" signal-exit "^3.0.2" -ret@~0.1.10: - version "0.1.15" - resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" - integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== - reusify@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" @@ -6100,23 +5174,11 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" - integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= - dependencies: - ret "~0.1.10" - "safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sanitize-s3-objectkey@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/sanitize-s3-objectkey/-/sanitize-s3-objectkey-0.0.1.tgz#efa9887cd45275b40234fb4bb12fc5754fe64e7e" - integrity sha512-ZTk7aqLxy4sD40GWcYWoLfbe05XLmkKvh6vGKe13ADlei24xlezcvjgKy1qRArlaIbIMYaqK7PCalvZtulZlaQ== - sax@1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" @@ -6134,11 +5196,6 @@ saxes@^5.0.1: dependencies: xmlchars "^2.2.0" -self-closing-tags@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/self-closing-tags/-/self-closing-tags-1.0.1.tgz#6c5fa497994bb826b484216916371accee490a5d" - integrity sha512-7t6hNbYMxM+VHXTgJmxwgZgLGktuXtVVD5AivWzNTdJBM4DBjnDKDzkf2SrNjihaArpeJYNjxkELBu1evI4lQA== - semver-diff@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-3.1.1.tgz#05f77ce59f325e00e2706afd67bb506ddb1ca32b" @@ -6153,7 +5210,7 @@ semver@7.x, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5: dependencies: lru-cache "^6.0.0" -semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.1: +semver@^5.5.0, semver@^5.6.0, semver@^5.7.1: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -6168,16 +5225,6 @@ server-destroy@^1.0.1: resolved "https://registry.yarnpkg.com/server-destroy/-/server-destroy-1.0.1.tgz#f13bf928e42b9c3e79383e61cc3998b5d14e6cdd" integrity sha1-8Tv5KOQrnD55OD5hzDmYtdFObN0= -set-value@^2.0.0, set-value@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" - integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.3" - split-string "^3.0.1" - setprototypeof@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" @@ -6212,11 +5259,6 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -shimmer@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" - integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw== - side-channel@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" @@ -6250,36 +5292,6 @@ slice-ansi@^2.1.0: astral-regex "^1.0.0" is-fullwidth-code-point "^2.0.0" -snapdragon-node@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" - integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== - dependencies: - define-property "^1.0.0" - isobject "^3.0.0" - snapdragon-util "^3.0.1" - -snapdragon-util@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" - integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== - dependencies: - kind-of "^3.2.0" - -snapdragon@^0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" - integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== - dependencies: - base "^0.11.1" - debug "^2.2.0" - define-property "^0.2.5" - extend-shallow "^2.0.1" - map-cache "^0.2.2" - source-map "^0.5.6" - source-map-resolve "^0.5.0" - use "^3.1.0" - sonic-boom@^1.0.2: version "1.4.1" resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-1.4.1.tgz#d35d6a74076624f12e6f917ade7b9d75e918f53e" @@ -6288,17 +5300,6 @@ sonic-boom@^1.0.2: atomic-sleep "^1.0.0" flatstr "^1.0.12" -source-map-resolve@^0.5.0: - version "0.5.3" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" - integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== - dependencies: - atob "^2.1.2" - decode-uri-component "^0.2.0" - resolve-url "^0.2.1" - source-map-url "^0.4.0" - urix "^0.1.0" - source-map-support@^0.5.6: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" @@ -6307,11 +5308,6 @@ source-map-support@^0.5.6: buffer-from "^1.0.0" source-map "^0.6.0" -source-map-url@^0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" - integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== - source-map@^0.4.2: version "0.4.4" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" @@ -6319,7 +5315,7 @@ source-map@^0.4.2: dependencies: amdefine ">=0.0.4" -source-map@^0.5.0, source-map@^0.5.6, source-map@~0.5.0: +source-map@^0.5.0, source-map@~0.5.0: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= @@ -6339,13 +5335,6 @@ spark-md5@3.0.1: resolved "https://registry.yarnpkg.com/spark-md5/-/spark-md5-3.0.1.tgz#83a0e255734f2ab4e5c466e5a2cfc9ba2aa2124d" integrity sha512-0tF3AGSD1ppQeuffsLDIOWlKUd3lS92tFxcsrh5Pe3ZphhnoK+oXIBTzOAThZCiuINZLvpiLH/1VS1/ANEJVig== -split-string@^3.0.1, split-string@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" - integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== - dependencies: - extend-shallow "^3.0.0" - split2@^3.1.1: version "3.2.2" resolved "https://registry.yarnpkg.com/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f" @@ -6373,11 +5362,6 @@ sshpk@^1.7.0: safer-buffer "^2.0.2" tweetnacl "~0.14.0" -stack-chain@^1.3.7: - version "1.3.7" - resolved "https://registry.yarnpkg.com/stack-chain/-/stack-chain-1.3.7.tgz#d192c9ff4ea6a22c94c4dd459171e3f00cea1285" - integrity sha1-0ZLJ/06moiyUxN1FkXHj8AzqEoU= - stack-utils@^2.0.3: version "2.0.5" resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" @@ -6385,19 +5369,6 @@ stack-utils@^2.0.3: dependencies: escape-string-regexp "^2.0.0" -standard-as-callback@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45" - integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A== - -static-extend@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" - integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= - dependencies: - define-property "^0.2.5" - object-copy "^0.1.0" - "statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" @@ -6421,11 +5392,6 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" -string-template@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/string-template/-/string-template-1.0.0.tgz#9e9f2233dc00f218718ec379a28a5673ecca8b96" - integrity sha1-np8iM9wA8hhxjsN5oopWc+zKi5Y= - string-width@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" @@ -6497,11 +5463,6 @@ strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= -striptags@^3.1.1: - version "3.2.0" - resolved "https://registry.yarnpkg.com/striptags/-/striptags-3.2.0.tgz#cc74a137db2de8b0b9a370006334161f7dd67052" - integrity sha512-g45ZOGzHDMe2bdYMdIvdAfCQkCTDMGBazSw1ypMowwGIee7ZQ5dU0rBJ8Jqgl+jAKIv4dbeE1jscZq9wid1Tkw== - sublevel-pouchdb@7.2.2: version "7.2.2" resolved "https://registry.yarnpkg.com/sublevel-pouchdb/-/sublevel-pouchdb-7.2.2.tgz#49e46cd37883bf7ff5006d7c5b9bcc7bcc1f422f" @@ -6586,27 +5547,6 @@ table@^5.2.3: slice-ansi "^2.1.0" string-width "^3.0.0" -tar-fs@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" - integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng== - dependencies: - chownr "^1.1.1" - mkdirp-classic "^0.5.2" - pump "^3.0.0" - tar-stream "^2.1.4" - -tar-stream@^2.1.4: - version "2.2.0" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" - integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== - dependencies: - bl "^4.0.3" - end-of-stream "^1.4.1" - fs-constants "^1.0.0" - inherits "^2.0.3" - readable-stream "^3.1.1" - terminal-link@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" @@ -6642,7 +5582,7 @@ through2@3.0.2: inherits "^2.0.4" readable-stream "2 || 3" -through2@^2.0.0, through2@^2.0.1: +through2@^2.0.1: version "2.0.5" resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== @@ -6682,31 +5622,11 @@ to-fast-properties@^2.0.0: resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= -to-gfm-code-block@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/to-gfm-code-block/-/to-gfm-code-block-0.1.1.tgz#25d045a5fae553189e9637b590900da732d8aa82" - integrity sha1-JdBFpfrlUxielje1kJANpzLYqoI= - -to-object-path@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" - integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= - dependencies: - kind-of "^3.0.2" - to-readable-stream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== -to-regex-range@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" - integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= - dependencies: - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -6714,16 +5634,6 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -to-regex@^3.0.1, to-regex@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" - integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== - dependencies: - define-property "^2.0.2" - extend-shallow "^3.0.2" - regex-not "^1.0.2" - safe-regex "^1.1.0" - toidentifier@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" @@ -6868,23 +5778,11 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" -typeof-article@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/typeof-article/-/typeof-article-0.1.1.tgz#9f07e733c3fbb646ffa9e61c08debacd460e06af" - integrity sha1-nwfnM8P7tkb/qeYcCN66zUYOBq8= - dependencies: - kind-of "^3.1.0" - typescript@4.5.5: version "4.5.5" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3" integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA== -uglify-js@^3.1.4: - version "3.15.4" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.15.4.tgz#fa95c257e88f85614915b906204b9623d4fa340d" - integrity sha512-vMOPGDuvXecPs34V74qDKk4iJ/SN4vL3Ow/23ixafENYvtrNvtbcgUeugTcUGRGsOF/5fU8/NYSL5Hyb3l1OJA== - uid2@0.0.x: version "0.0.4" resolved "https://registry.yarnpkg.com/uid2/-/uid2-0.0.4.tgz#033f3b1d5d32505f5ce5f888b9f3b667123c0a44" @@ -6895,16 +5793,6 @@ undefsafe@^2.0.5: resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c" integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA== -union-value@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" - integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== - dependencies: - arr-union "^3.1.0" - get-value "^2.0.6" - is-extendable "^0.1.1" - set-value "^2.0.1" - unique-string@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" @@ -6922,14 +5810,6 @@ unpipe@1.0.0: resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= -unset-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" - integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= - dependencies: - has-value "^0.3.1" - isobject "^3.0.0" - untildify@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" @@ -6972,11 +5852,6 @@ urijs@^1.19.2: resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.8.tgz#ee0407a18528934d3c383e691912f47043a58feb" integrity sha512-iIXHrjomQ0ZCuDRy44wRbyTZVnfVNLVo3Ksz1yxNyE5wV1IDZW2S5Jszy45DTlw/UdsnRT7DyDhIz7Gy+vJumw== -urix@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" - integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= - url-parse-lax@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" @@ -6992,11 +5867,6 @@ url@0.10.3: punycode "1.3.2" querystring "0.2.0" -use@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" - integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== - util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -7022,11 +5892,6 @@ uuid@^3.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== -uuid@^8.3.2: - version "8.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== - v8-compile-cache@^2.0.3: version "2.3.0" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" @@ -7055,14 +5920,6 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" -vm2@^3.9.4: - version "3.9.9" - resolved "https://registry.yarnpkg.com/vm2/-/vm2-3.9.9.tgz#c0507bc5fbb99388fad837d228badaaeb499ddc5" - integrity sha512-xwTm7NLh/uOjARRBs8/95H0e8fT3Ukw5D/JJWhxMbhKzNh1Nu981jQKvkep9iKYNxzlVrdzD0mlBGkDKZWprlw== - dependencies: - acorn "^8.7.0" - acorn-walk "^8.2.0" - vuvuzela@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/vuvuzela/-/vuvuzela-1.0.3.tgz#3be145e58271c73ca55279dd851f12a682114b0b" @@ -7167,11 +6024,6 @@ word-wrap@~1.2.3: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== -wordwrap@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= - wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" @@ -7283,11 +6135,6 @@ yargs@^16.1.0, yargs@^16.2.0: y18n "^5.0.5" yargs-parser "^20.2.2" -year@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/year/-/year-0.2.1.tgz#4083ae520a318b23ec86037f3000cb892bdf9bb0" - integrity sha1-QIOuUgoxiyPshgN/MADLiSvfm7A= - ylru@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/ylru/-/ylru-1.2.1.tgz#f576b63341547989c1de7ba288760923b27fe84f" @@ -7297,8 +6144,3 @@ yn@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== - -zlib@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/zlib/-/zlib-1.0.5.tgz#6e7c972fc371c645a6afb03ab14769def114fcc0" - integrity sha1-bnyXL8NxxkWmr7A6sUdp3vEU/MA= diff --git a/yarn.lock b/yarn.lock index 9dff955ab3..129b650c73 100644 --- a/yarn.lock +++ b/yarn.lock @@ -818,11 +818,32 @@ call-me-maybe "^1.0.1" glob-to-regexp "^0.3.0" +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + "@nodelib/fs.stat@^1.1.2": version "1.1.3" resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b" integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + "@octokit/auth-token@^2.4.0": version "2.5.0" resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.5.0.tgz#27c37ea26c205f28443402477ffd261311f21e36" @@ -971,6 +992,50 @@ resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw== +"@typescript-eslint/parser@4.28.0": + version "4.28.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.28.0.tgz#2404c16751a28616ef3abab77c8e51d680a12caa" + integrity sha512-7x4D22oPY8fDaOCvkuXtYYTQ6mTMmkivwEzS+7iml9F9VkHGbbZ3x4fHRwxAb5KeuSkLqfnYjs46tGx2Nour4A== + dependencies: + "@typescript-eslint/scope-manager" "4.28.0" + "@typescript-eslint/types" "4.28.0" + "@typescript-eslint/typescript-estree" "4.28.0" + debug "^4.3.1" + +"@typescript-eslint/scope-manager@4.28.0": + version "4.28.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.28.0.tgz#6a3009d2ab64a30fc8a1e257a1a320067f36a0ce" + integrity sha512-eCALCeScs5P/EYjwo6se9bdjtrh8ByWjtHzOkC4Tia6QQWtQr3PHovxh3TdYTuFcurkYI4rmFsRFpucADIkseg== + dependencies: + "@typescript-eslint/types" "4.28.0" + "@typescript-eslint/visitor-keys" "4.28.0" + +"@typescript-eslint/types@4.28.0": + version "4.28.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.28.0.tgz#a33504e1ce7ac51fc39035f5fe6f15079d4dafb0" + integrity sha512-p16xMNKKoiJCVZY5PW/AfILw2xe1LfruTcfAKBj3a+wgNYP5I9ZEKNDOItoRt53p4EiPV6iRSICy8EPanG9ZVA== + +"@typescript-eslint/typescript-estree@4.28.0": + version "4.28.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.28.0.tgz#e66d4e5aa2ede66fec8af434898fe61af10c71cf" + integrity sha512-m19UQTRtxMzKAm8QxfKpvh6OwQSXaW1CdZPoCaQuLwAq7VZMNuhJmZR4g5281s2ECt658sldnJfdpSZZaxUGMQ== + dependencies: + "@typescript-eslint/types" "4.28.0" + "@typescript-eslint/visitor-keys" "4.28.0" + debug "^4.3.1" + globby "^11.0.3" + is-glob "^4.0.1" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/visitor-keys@4.28.0": + version "4.28.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.28.0.tgz#255c67c966ec294104169a6939d96f91c8a89434" + integrity sha512-PjJyTWwrlrvM5jazxYF5ZPs/nl0kHDZMVbuIcbpawVXaDPelp3+S9zpOz5RmVUfS/fD5l5+ZXNKnWhNYjPzCvw== + dependencies: + "@typescript-eslint/types" "4.28.0" + eslint-visitor-keys "^2.0.0" + JSONStream@^1.0.4, JSONStream@^1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" @@ -1146,6 +1211,11 @@ array-union@^1.0.1: dependencies: array-uniq "^1.0.1" +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + array-uniq@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" @@ -1284,6 +1354,13 @@ braces@^2.3.1: split-string "^3.0.2" to-regex "^3.0.1" +braces@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + btoa-lite@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/btoa-lite/-/btoa-lite-1.0.0.tgz#337766da15801210fdd956c22e9c6891ab9d0337" @@ -1825,6 +1902,13 @@ debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: dependencies: ms "2.1.2" +debug@^4.3.1: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + debuglog@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" @@ -1930,6 +2014,13 @@ dir-glob@2.0.0: arrify "^1.0.1" path-type "^3.0.0" +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + doctrine@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" @@ -2306,6 +2397,17 @@ fast-glob@^2.0.2: merge2 "^1.2.3" micromatch "^3.1.10" +fast-glob@^3.2.9: + version "3.2.11" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" + integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" @@ -2316,6 +2418,13 @@ fast-levenshtein@^2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= +fastq@^1.6.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" + integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== + dependencies: + reusify "^1.0.4" + figgy-pudding@^3.4.1, figgy-pudding@^3.5.1: version "3.5.2" resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e" @@ -2345,6 +2454,13 @@ fill-range@^4.0.0: repeat-string "^1.6.1" to-regex-range "^2.1.0" +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + filter-obj@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-1.1.0.tgz#9b311112bc6c6127a16e016c6c5d7f19e0805c5b" @@ -2655,6 +2771,18 @@ globals@^13.6.0, globals@^13.9.0: dependencies: type-fest "^0.20.2" +globby@^11.0.3: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + globby@^8.0.1: version "8.0.2" resolved "https://registry.yarnpkg.com/globby/-/globby-8.0.2.tgz#5697619ccd95c5275dbb2d6faa42087c1a941d8d" @@ -2863,6 +2991,11 @@ ignore@^4.0.6: resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== +ignore@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" + integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== + import-fresh@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" @@ -3158,6 +3291,11 @@ is-number@^3.0.0: dependencies: kind-of "^3.0.2" +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + is-obj@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" @@ -3742,7 +3880,7 @@ meow@^8.0.0: type-fest "^0.18.0" yargs-parser "^20.2.3" -merge2@^1.2.3: +merge2@^1.2.3, merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== @@ -3766,6 +3904,14 @@ micromatch@^3.1.10: snapdragon "^0.8.1" to-regex "^3.0.2" +micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + mime-db@1.51.0: version "1.51.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c" @@ -3818,9 +3964,9 @@ minimist-options@^3.0.1: is-plain-obj "^1.1.0" minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== minipass@^2.3.5, minipass@^2.6.0, minipass@^2.9.0: version "2.9.0" @@ -4507,6 +4653,11 @@ path-type@^3.0.0: dependencies: pify "^3.0.0" +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" @@ -4517,6 +4668,11 @@ picomatch@^2.2.2: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + pify@^2.0.0, pify@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -4675,6 +4831,11 @@ query-string@^6.13.8: split-on-first "^1.0.0" strict-uri-encode "^2.0.0" +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + quick-lru@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8" @@ -4947,6 +5108,11 @@ retry@^0.10.0: resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4" integrity sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q= +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + rimraf@2, rimraf@^2.5.4, rimraf@^2.6.2, rimraf@^2.6.3: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" @@ -4981,6 +5147,13 @@ run-async@^2.2.0: resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + run-queue@^1.0.0, run-queue@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" @@ -5027,7 +5200,7 @@ semver@^6.0.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.2.1, semver@^7.3.4: +semver@^7.2.1, semver@^7.3.4, semver@^7.3.5: version "7.3.5" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== @@ -5102,6 +5275,11 @@ slash@^1.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + slice-ansi@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" @@ -5581,6 +5759,13 @@ to-regex-range@^2.1.0: is-number "^3.0.0" repeat-string "^1.6.1" +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + to-regex@^3.0.1, to-regex@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" @@ -5626,11 +5811,18 @@ trim-newlines@^3.0.0: resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw== -tslib@^1.9.0: +tslib@^1.8.1, tslib@^1.9.0: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" @@ -5675,6 +5867,11 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= +typescript@4.5.5: + version "4.5.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3" + integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA== + uglify-js@^3.1.4: version "3.15.1" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.15.1.tgz#9403dc6fa5695a6172a91bc983ea39f0f7c9086d"