diff --git a/.gitignore b/.gitignore index bdab34cb367..e77268e6010 100644 --- a/.gitignore +++ b/.gitignore @@ -47,3 +47,7 @@ python_data_import/debug.log.txt python_data_import/logs.txt python_data_import/date.txt */__pycache__/ + +# Local-dev compose env created by copying docker/.env.local.example. Per-developer, +# never committed. The .example template IS committed. +/docker/.env.local diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000000..1117d417c6a --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +18.20.5 diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000000..19e7914de4d --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,206 @@ +# AGENTS.md — testing this branch (dataquest dspace-angular) + +Goal: spin up the **backend in Docker** and the **frontend natively** (live-editable +`ng serve`) and confirm they talk to each other, with the fewest moving parts. + +Validated end-to-end on `internal/unify-docker-compose` (Windows + Docker Desktop, Compose +v2.40): BE up from one `.env.local`, FE on `ng serve` rendering the LINDAT/CLARIAH-CZ home in +a real browser with demo content (6 communities, 471 indexed items), 200s, no CORS errors. +Builds on PR #1289, which makes `docker/docker-compose-rest.yml` drivable from one `--env-file`. + +> Several non-obvious traps below cost real time to find — read **Gotchas** before starting. +> **Match the BE to the FE version:** this FE reports **7.6.5** (see the browser console +> startup banner), so use a **7.6.5** backend image. A 7.5 BE (`dtq-dev-7.5`) parses most +> things but errors on browse definitions. + +--- + +## Prerequisites + +- **Docker** running. +- **Node 18** for the frontend. NOT 20+/24 — the Angular 15 toolchain breaks on newer Node in + ways CI doesn't catch (CI runs `build:prod`, never `ng serve`). Portable install, no global + change: + ```bash + D=/c/Users/$USER/AppData/Local/Temp/node18setup; mkdir -p "$D" && cd "$D" + curl -fsSL -o n18.zip https://nodejs.org/dist/v18.20.5/node-v18.20.5-win-x64.zip + /c/Windows/System32/tar.exe -xf n18.zip # MSYS tar can't unzip; use Windows bsdtar + ./node-v18.20.5-win-x64/npm.cmd install -g yarn@1.22.19 + export PATH="$D/node-v18.20.5-win-x64:$PATH" # prepend for FE commands + ``` +- **The `ng serve` fix** (Gotcha #2): the branch pins `copy-webpack-plugin@^6.4.1`, which + breaks `ng serve`. Bump it to `^11.0.0` in `package.json` and `yarn install`. (This is now + committed on PR #1289.) + +--- + +## TL;DR — two commands + +```bash +# 0) one-time: use Node 18 (see .nvmrc) and install deps +nvm use # or: see Prerequisites for a portable Node 18 +yarn install + +# 1) BACKEND: DSpace 7.6.5 + demo content at http://127.0.0.1:8087/server (~2-4 min first run) +build-scripts/run/dev.backend.sh # add 'fresh' to wipe volumes + reload from scratch + +# 2) FRONTEND: live-reload dev server on http://localhost:4000 +yarn start:dev:local +``` + +`dev.backend.sh` brings the backend up (correct 7.6.5 images, IPv4 host, CORS, demo dataset) +and reindexes Solr; `start:dev:local` is `ng serve` with the right `DSPACE_REST_*` env baked in. +Stop/wipe the backend with `docker compose -f docker/docker-compose-rest.yml -f docker/db.entities.yml down -v`. + +Everything below is the manual/explained version of those two commands (for customizing the +instance, image set, or running the FE in Docker). The FE maps env vars onto `config/config.yml` +(`rest.host`→`DSPACE_REST_HOST`, … ; env wins last — see `src/config/config.server.ts`). + +--- + +## Backend (Docker) + +`docker/docker-compose-rest.yml` fully defines the network, so the BE comes up from that file +(plus `db.entities.yml` for demo data) — no `docker-compose.yml` (that's the FE container). + +`docker/.env.local` for this recipe: + +```ini +INSTANCE=7 +# 127.0.0.1, NOT localhost (Gotcha #5). BE self-links use REST_URL, so keep it on 127.0.0.1. +DSPACE_HOST=127.0.0.1 +DSPACE_REST_PORT=808${INSTANCE} # -> 8087 +DSPACE_REST_NAMESPACE=/server +REST_URL=http://127.0.0.1:808${INSTANCE}/server +UI_URL=http://localhost:4000 # native FE dev-server port, NOT 400${INSTANCE} +HOST_IP=127.0.0.1 +DSPACE_SUBNET_PREFIX=10.10${INSTANCE} +REST_CORS_ALLOWED_ORIGINS=http://localhost:4000,http://127.0.0.1:4000 + +# --- Option A: demo content (VERIFIED) — upstream 7.6.5 + db.entities.yml ------------------- +# Matches the FE's 7.6.5 and loads the official DSpace demo entities dataset. NOTE: this is +# UPSTREAM DSpace data on an UPSTREAM BE, so CLARIN-specific FE calls 404 (harmless to render). +DSPACE_REST_IMAGE=dspace/dspace:dspace-7_x +DSPACE_DB_IMAGE=dspace/dspace-postgres-pgcrypto:dspace-7_x # db.entities.yml overrides to -loadsql +DSPACE_SOLR_IMAGE=dspace/dspace-solr:dspace-7_x +DOCKER_REGISTRY=docker.io # consumed by db.entities.yml to resolve the -loadsql image +DOCKER_OWNER=dspace +DSPACE_VER=dspace-7_x + +# --- Option B: CLARIN fidelity (version-matched, but no content unless you have a dump) ------ +# DSPACE_REST_IMAGE=dataquest/dspace:dspace-7_x # DSpace 7.6.5, CLARIN tables/endpoints +# DSPACE_DB_IMAGE=dataquest/dspace-postgres-pgcrypto:dspace-7_x +# DSPACE_SOLR_IMAGE=dataquest/dspace-solr:dspace-7_x +# Fresh DB = empty homepage. For real CLARIN content, restore a dataquest/LINDAT DB dump into +# dspacedb7 (pg_restore/psql) instead of layering db.entities.yml, then reindex. +``` + +- Bring up Option A with **both** files: `-f docker/docker-compose-rest.yml -f docker/db.entities.yml`. + The `-loadsql` Postgres downloads + imports `dspace7-entities-data.sql` on first boot; the BE + then runs `database migrate ignored`. **Then reindex Solr** (command above) or the homepage's + browse/search/"What's New" stay empty even though the DB has data. +- For Option B (no `db.entities.yml`), use just `-f docker/docker-compose-rest.yml`. +- **Ports** (INSTANCE=7): REST `8087`, JVM debug `8007`, Postgres `5437`, Solr `8987`. Change + `INSTANCE` to re-target all at once. 5 and 8 are reserved by `.github/workflows/deploy.yml`. +- Admin user (optional): `… -f docker/cli.yml run --rm dspace-cli create-administrator -e admin@test.dev -f admin -l user -p admin -c en -o dataquest` + +### Verify the BE +```bash +curl -s http://127.0.0.1:8087/server/api # dspaceVersion => DSpace 7.6.5 +curl -s http://127.0.0.1:8087/server/api/core/communities/search/top # totalElements: 6 (demo) +curl -s -i -X OPTIONS http://127.0.0.1:8087/server/api/core/items \ + -H 'Origin: http://localhost:4000' -H 'Access-Control-Request-Method: GET' \ + | grep -i access-control-allow-origin # => http://localhost:4000 +``` + +--- + +## Frontend (native, live-editable) + +```bash +export PATH="/c/Users/$USER/AppData/Local/Temp/node18setup/node-v18.20.5-win-x64:$PATH" +yarn install # after the copy-webpack-plugin bump, or if node_modules is partial +DSPACE_REST_SSL=false DSPACE_REST_HOST=127.0.0.1 DSPACE_REST_PORT=8087 \ + DSPACE_UI_HOST=localhost DSPACE_UI_PORT=4000 \ + yarn start:dev # ng serve, live-reload, http://localhost:4000 +``` + +- `yarn start:dev` = `ng serve` (CSR dev server, fast rebuilds — what you want for editing). + `yarn start` does a full SSR production build instead. +- The browser calls the BE directly at `http://127.0.0.1:8087/server`; the CORS list must include + `http://localhost:4000` (it does). +- Don't set `DSPACE_REST_NAMESPACE` from a Git-Bash shell (Gotcha #1); config default `/server` + is correct. + +### What success looks like +`http://localhost:4000` redirects to `/home` and renders the **LINDAT/CLARIAH-CZ Repository +Home**: search + facets (Author/Subject/Language), a **"What's New"** list of items, and the +footer. DevTools → Network shows `…8087/server/api/*` 200s with no CORS errors. Benign console +errors are normal: `favicon.ico` 404, Matomo refused, `google.analytics.key` 404, `/security/csrf` +404, and (with Option A's upstream BE) some CLARIN-specific 404s. + +--- + +## Gotchas (each one cost time to find) + +1. **Git Bash mangles leading-slash paths.** `DSPACE_REST_NAMESPACE=/server` becomes + `C:/Program Files/Git/server`, and `docker exec dspace7 /dspace/bin/dspace …` becomes + `…/Git/dspace/bin/dspace` (no such file). Fix: prefix the command with + `MSYS_NO_PATHCONV=1 MSYS2_ARG_CONV_EXCL='*'`. (Values inside the `.env.local` file are NOT + mangled — only shell args.) + +2. **`ng serve` is broken on this branch out of the box.** `package.json` pins + `copy-webpack-plugin@^6.4.1`, but build-angular@15 (via `@angular-builders/custom-webpack`) + emits asset-copy patterns using the `priority` option (v9+) → `Copy Plugin … unknown property + 'priority'`. CI misses it (it runs `build:prod`, not `ng serve`). Fix: `^11.0.0` (matches + build-angular) + `yarn install`. (Committed on PR #1289.) + +3. **Stale / partial `node_modules`.** `Can't resolve 'd3'` / `'ngx-skeleton-loader'` + a cascade + of `NG6002`/`NG8004` → run a full `yarn install`. + +4. **Stale Postgres volume version mismatch.** Re-using an old `dspace-7_pgdata` initialised by a + different Postgres major gives `FATAL: database files are incompatible with server`; the BE + then hangs forever in its DB-wait loop. Fix: `down -v` for a clean start (`--remove-orphans` + clears a leftover `dspace-angular` container). + +5. **`localhost` ≠ `127.0.0.1` for the FE→BE hop.** Node 18 resolves `localhost` to IPv6 `::1` + with no IPv4 fallback, but the BE publishes on `127.0.0.1` only, so Node fetches `ECONNREFUSED` + → `undefined doesn't contain the link sites`. Worse, a host MISMATCH (FE on `127.0.0.1` but BE + self-links on `localhost`) made the HAL parser resolve objects under two hostnames and recurse + → `RangeError: Maximum call stack size exceeded` in `DspaceRestResponseParsingService`. Keep + **both** `DSPACE_REST_HOST` and `REST_URL` on `127.0.0.1`. (`curl` hides this — it falls back + to IPv4.) + +6. **Match the BE to the FE version.** The FE reports **7.6.5**, so use a **7.6.5** BE + (`dspace/dspace:dspace-7_x` or `dataquest/dspace:dspace-7_x`). The `dataquest/dspace:dtq-dev-7.5` + image is **DSpace 7.5** and causes `An error occurred while retrieving the browse definitions` + in the console. + +7. **Demo data ≠ empty repo, and Solr needs reindexing.** A fresh DB shows an empty homepage — + that's expected, not a bug. Layer `db.entities.yml` (Option A) for sample content, then run + `index-discovery -b` so browse/search/"What's New" populate. (The public + `dspace7-entities-data.sql` now ships future 8.0/9.0/10.0 flyway entries; a 7.6.5 BE still + reads the data fine via `migrate ignored`.) + +8. **Orphaned `ng serve` keeps port 4000.** Stopping `nodemon` doesn't kill its `ng serve` child, + so the next start crashes on `Port 4000 is already in use`. Kill the listener first: + ```bash + pid=$(netstat -ano | grep LISTENING | grep ':4000' | awk '{print $NF}' | head -1) + taskkill //F //T //PID $pid + ``` + And do NOT switch git branches while `ng serve` runs — it watches the working tree and will + recompile against the wrong files. Stop it first (or use a separate `git worktree`). + +--- + +## Alternative: fully containerized FE (PR #1289's documented path) + +To run the FE in Docker too, use `docker/.env.local.example` as-is (`host.docker.internal`, +`HOST_IP=0.0.0.0`, CORS on `400${INSTANCE}`) and bring up **both** compose files with `--build`: +```bash +docker compose --env-file docker/.env.local \ + -f docker/docker-compose.yml -f docker/docker-compose-rest.yml up -d --build +# FE on http://localhost:4007 ; this build path exercises the Dockerfile cp fix from PR #1289. +``` +`HOST_IP=0.0.0.0` publishes every BE port (incl. Postgres pwd `dspace`, JVM debug) on all +interfaces — dev-only, not for an untrusted network. diff --git a/Dockerfile b/Dockerfile index e1e72cbf43f..206540f1a97 100644 --- a/Dockerfile +++ b/Dockerfile @@ -28,5 +28,13 @@ ENV NODE_ENV=development RUN apk add tzdata RUN yarn build:prod RUN npm install pm2 -g -CMD /bin/sh -c "pm2-runtime start docker/dspace-ui.json > /dev/null 2> /dev/null" + +# Mirror Dockerfile.dist's layout so docker-compose.yml's entrypoint +# (`pm2-runtime start dspace-ui.json`, no `docker/` prefix) works for both +# the locally-built dev image and the published dist image. Before this, +# locally-built containers ENOENT-looped because compose's entrypoint +# pointed at the dist path while the file sat at /app/docker/dspace-ui.json. +RUN cp docker/dspace-ui.json /app/dspace-ui.json + +CMD /bin/sh -c "pm2-runtime start dspace-ui.json > /dev/null 2> /dev/null" diff --git a/build-scripts/run/dev.backend.sh b/build-scripts/run/dev.backend.sh new file mode 100644 index 00000000000..15d42a8273b --- /dev/null +++ b/build-scripts/run/dev.backend.sh @@ -0,0 +1,76 @@ +#!/usr/bin/env bash +# +# One-command local-dev BACKEND for working on the native frontend. +# +# Brings up a DSpace 7.6.5 backend (matching this FE's version) in Docker, loaded with the +# official demo entities dataset, reachable at http://127.0.0.1:8087/server, then indexes Solr +# so browse/search/"What's New" are populated. After it prints "Backend ready", start the FE: +# +# yarn start:dev:local # ng serve, live-reload, http://localhost:4000 (needs Node 18 — see .nvmrc) +# +# Usage: +# build-scripts/run/dev.backend.sh # up (reuses existing containers/data) +# build-scripts/run/dev.backend.sh fresh # wipe DB/Solr volumes first, then up (clean slate) +# +# Notes: +# - 127.0.0.1 (not localhost): Node resolves localhost to IPv6 ::1, but the BE binds IPv4 only. +# - Demo data is UPSTREAM DSpace (not CLARIN), so some CLARIN-specific FE calls 404 — harmless. +# For CLARIN content, point DSPACE_REST_IMAGE at dataquest/dspace:dspace-7_x and restore a +# dataquest/LINDAT DB dump instead of using db.entities.yml. +# +set -uo pipefail +cd "$(dirname "$0")/../.." || exit 1 + +export INSTANCE="${INSTANCE:-7}" +export COMPOSE_PROJECT_NAME="dspace-${INSTANCE}" +export DSPACE_HOST=127.0.0.1 +export DSPACE_REST_NAMESPACE=/server +export REST_URL="http://127.0.0.1:808${INSTANCE}/server" +export UI_URL="http://localhost:4000" +export HOST_IP=127.0.0.1 +export DSPACE_SUBNET_PREFIX="10.10${INSTANCE}" +export REST_CORS_ALLOWED_ORIGINS="http://localhost:4000,http://127.0.0.1:4000" +# DSpace 7.6.5 to match the FE; upstream images + the demo entities dataset (db.entities.yml). +export DSPACE_REST_IMAGE=dspace/dspace:dspace-7_x +export DSPACE_DB_IMAGE=dspace/dspace-postgres-pgcrypto:dspace-7_x +export DSPACE_SOLR_IMAGE=dspace/dspace-solr:dspace-7_x +export DOCKER_REGISTRY=docker.io DOCKER_OWNER=dspace DSPACE_VER=dspace-7_x + +COMPOSE=(docker compose -f docker/docker-compose-rest.yml -f docker/db.entities.yml) +REST="http://127.0.0.1:808${INSTANCE}/server/api" + +if [ "${1:-}" = "fresh" ]; then + echo ">> wiping previous dev backend (down -v)" + "${COMPOSE[@]}" down -v --remove-orphans || true +fi + +echo ">> starting backend: DSpace 7.6.5 + demo entities (project ${COMPOSE_PROJECT_NAME})" +if ! "${COMPOSE[@]}" up -d; then + echo "!! 'up' failed. If it's a Postgres version/volume mismatch, run: $0 fresh" >&2 + exit 1 +fi + +echo -n ">> waiting for REST API (${REST}) " +for _ in $(seq 1 90); do + [ "$(curl -s -o /dev/null -w '%{http_code}' "$REST" 2>/dev/null)" = "200" ] && { echo " ready"; break; } + printf '.'; sleep 5 +done +if [ "$(curl -s -o /dev/null -w '%{http_code}' "$REST" 2>/dev/null)" != "200" ]; then + echo " timed out. Check: ${COMPOSE[*]} logs dspace${INSTANCE}" >&2 + exit 1 +fi + +echo ">> indexing Solr discovery (so browse/search/What's New populate)" +# MSYS_NO_PATHCONV stops Git Bash from rewriting /dspace/... into a Windows path. +MSYS_NO_PATHCONV=1 docker exec "dspace${INSTANCE}" /dspace/bin/dspace index-discovery -b \ + || echo " (reindex failed — rerun: MSYS_NO_PATHCONV=1 docker exec dspace${INSTANCE} /dspace/bin/dspace index-discovery -b)" + +cat <:400${INSTANCE} here too. +REST_CORS_ALLOWED_ORIGINS=http://localhost:400${INSTANCE},http://host.docker.internal:400${INSTANCE},http://127.0.0.1:400${INSTANCE} + +# Image set. Use the upstream `dspace/*` images when seeding the DB with the standard +# entities SQL (docker/db.entities.yml) — the dataquest BE has CLARIN-specific tables +# that the upstream SQL dump doesn't create. Switch to the dataquest set when running +# against a dataquest-compatible database dump. +DSPACE_UI_IMAGE=dataquest/dspace-angular:dspace-7_x +DSPACE_REST_IMAGE=dspace/dspace:dspace-7_x +DSPACE_DB_IMAGE=dspace/dspace-postgres-pgcrypto:dspace-7_x +DSPACE_SOLR_IMAGE=dspace/dspace-solr:dspace-7_x + +# Required by docker/db.entities.yml's image expansion if you layer that file in to +# preload the entities demo data (the loadsql variant downloads + imports the SQL +# dump on first start). +DOCKER_REGISTRY=docker.io +DOCKER_OWNER=dspace +DSPACE_VER=dspace-7_x diff --git a/docker/docker-compose-rest.yml b/docker/docker-compose-rest.yml index bade0ecf24a..74553f773ae 100644 --- a/docker/docker-compose-rest.yml +++ b/docker/docker-compose-rest.yml @@ -17,8 +17,10 @@ networks: ipam: config: # Define a custom subnet for our DSpace network, so that we can easily trust requests from host to container. - # If you customize this value, be sure to customize the 'proxies.trusted.ipranges' env variable below. - - subnet: 172.2${INSTANCE}.0.0/16 + # The 172.2X.0.0/16 default is the historical pyinfra-deployed layout and stays unchanged for + # production. Local-dev hosts often already have the 172.2X range occupied by unrelated compose + # projects; override with DSPACE_SUBNET_PREFIX (e.g. `10.10${INSTANCE}`) in the .env file. + - subnet: ${DSPACE_SUBNET_PREFIX:-172.2${INSTANCE}}.0.0/16 services: # DSpace (backend) webapp container dspace: @@ -40,8 +42,20 @@ services: # solr.server: Ensure we are using the 'dspacesolr' image for Solr solr__P__server: http://dspacesolr:8983/solr # proxies.trusted.ipranges: This setting is required for a REST API running in Docker to trust requests - # from the host machine. This IP range MUST correspond to the 'dspacenet' subnet defined above. - proxies__P__trusted__P__ipranges: '172.2${INSTANCE}.0' + # from the host machine. This IP range MUST correspond to the 'dspacenet' subnet defined above — + # follows DSPACE_SUBNET_PREFIX so an override there propagates here automatically. + proxies__P__trusted__P__ipranges: '${DSPACE_SUBNET_PREFIX:-172.2${INSTANCE}}.0' + # rest.cors.allowed-origins: comma-separated origin list the BE will respond to for CORS preflight. + # When REST_CORS_ALLOWED_ORIGINS is unset this defaults to ${UI_URL} (same literal as + # dspace.ui.url above), which equals the implicit ${dspace.ui.url} default that + # dspace/config/modules/rest.cfg already computes — so the effective CORS allow-list is + # unchanged for production / pyinfra. NOTE: this now sends rest.cors.allowed-origins as an + # explicit env override on every deploy (previously the BE derived it internally from + # rest.cfg); the value is the same, but it will shadow rest.cfg if that ever ships a + # non-default cors list. + # Local-dev sets REST_CORS_ALLOWED_ORIGINS to also include host.docker.internal and localhost + # so the browser preflight succeeds regardless of which name resolves the BE. + rest__P__cors__P__allowed__D__origins: ${REST_CORS_ALLOWED_ORIGINS:-${UI_URL:-http://127.0.0.1:4000}} #S3 config assetstore__P__index__P__primary: ${S3_STORAGE:-0} assetstore__P__s3__P__enabled: ${S3_ENABLED:-false} diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index ea0e5f30f1b..d760791eb42 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -30,10 +30,19 @@ services: volumes: - ./config.prod.yml:/app/config/config.prod.yml # - ./aai.js:/app/dist/browser/aai.js -# - ./dspace-ui.json:/app/docker/dspace-ui.json:rw +# - ./dspace-ui.json:/app/dspace-ui.json:rw build: context: .. dockerfile: Dockerfile + # host.docker.internal lets the FE container reach the BE through the host + # gateway when both are not on the same docker network (typical local-dev + # case where the FE is just the one container started from this file and + # the BE is reached at a host port). Docker Desktop on Mac/Windows already + # injects this; on Linux Docker (>= 20.10) `host-gateway` makes it resolve + # to the host. In production / pyinfra deploys this is a no-op because the + # BE is reached via its public DNS name (dev-5.pc etc.), not host.docker.internal. + extra_hosts: + - host.docker.internal:host-gateway networks: dspacenet: entrypoint: ${FE_CMD:-/bin/sh -c "pm2-runtime start dspace-ui.json > /dev/null 2> /dev/null"} diff --git a/package.json b/package.json index 565c0510999..f9682e4c5f4 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "test:rest": "ts-node --project ./tsconfig.ts-node.json scripts/test-rest.ts", "start": "yarn run start:prod", "start:dev": "nodemon --exec \"cross-env NODE_ENV=development yarn run serve\"", + "start:dev:local": "cross-env DSPACE_REST_SSL=false DSPACE_REST_HOST=127.0.0.1 DSPACE_REST_PORT=8087 DSPACE_UI_HOST=localhost DSPACE_UI_PORT=4000 yarn run start:dev", "start:prod": "yarn run build:prod && cross-env NODE_ENV=production yarn run serve:ssr", "start:mirador:prod": "yarn run build:mirador && yarn run start:prod", "preserve": "yarn base-href", @@ -166,7 +167,7 @@ "@typescript-eslint/parser": "^5.62.0", "axe-core": "^4.10.3", "compression-webpack-plugin": "^9.2.0", - "copy-webpack-plugin": "^6.4.1", + "copy-webpack-plugin": "^11.0.0", "cross-env": "^7.0.3", "csstype": "^3.1.3", "cypress": "^13.17.0", diff --git a/yarn.lock b/yarn.lock index 665ca9bbde2..9583ed80b33 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1669,7 +1669,7 @@ resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-6.7.2.tgz#8249de9b7e22fcb3ceb5e66090c30a1d5492b81a" integrity sha512-JUOtgFW6k9u4Y+xeIaEiLr3+cjoUPiAuLXoyKOJSia6Duzb7pq+A76P9ZdPDoAoxHdHzq6gE9/jKBGXlZT8FbA== -"@gar/promisify@^1.0.1", "@gar/promisify@^1.1.3": +"@gar/promisify@^1.1.3": version "1.1.3" resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== @@ -2018,14 +2018,6 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@npmcli/fs@^1.0.0": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-1.1.1.tgz#72f719fe935e687c56a4faecf3c03d06ba593257" - integrity sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ== - dependencies: - "@gar/promisify" "^1.0.1" - semver "^7.3.5" - "@npmcli/fs@^2.1.0": version "2.1.2" resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-2.1.2.tgz#a9e2541a4a2fec2e69c29b35e6060973da79b865" @@ -2063,14 +2055,6 @@ npm-bundled "^3.0.0" npm-normalize-package-bin "^3.0.0" -"@npmcli/move-file@^1.0.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.1.2.tgz#1a82c3e372f7cae9253eb66d72543d6b8685c674" - integrity sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg== - dependencies: - mkdirp "^1.0.4" - rimraf "^3.0.2" - "@npmcli/move-file@^2.0.0": version "2.0.1" resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-2.0.1.tgz#26f6bdc379d87f75e55739bab89db525b06100e4" @@ -4043,30 +4027,6 @@ cacache@17.0.4: tar "^6.1.11" unique-filename "^3.0.0" -cacache@^15.0.5: - version "15.3.0" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.3.0.tgz#dc85380fb2f556fe3dda4c719bfa0ec875a7f1eb" - integrity sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ== - dependencies: - "@npmcli/fs" "^1.0.0" - "@npmcli/move-file" "^1.0.1" - chownr "^2.0.0" - fs-minipass "^2.0.0" - glob "^7.1.4" - infer-owner "^1.0.4" - lru-cache "^6.0.0" - minipass "^3.1.1" - minipass-collect "^1.0.2" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.2" - mkdirp "^1.0.3" - p-map "^4.0.0" - promise-inflight "^1.0.1" - rimraf "^3.0.2" - ssri "^8.0.1" - tar "^6.0.2" - unique-filename "^1.1.1" - cacache@^16.1.0: version "16.1.3" resolved "https://registry.yarnpkg.com/cacache/-/cacache-16.1.3.tgz#a02b9f34ecfaf9a78c9f4bc16fceb94d5d67a38e" @@ -4587,7 +4547,7 @@ copy-to-clipboard@^3.3.1: dependencies: toggle-selection "^1.0.6" -copy-webpack-plugin@11.0.0: +copy-webpack-plugin@11.0.0, copy-webpack-plugin@^11.0.0: version "11.0.0" resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz#96d4dbdb5f73d02dd72d0528d1958721ab72e04a" integrity sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ== @@ -4599,23 +4559,6 @@ copy-webpack-plugin@11.0.0: schema-utils "^4.0.0" serialize-javascript "^6.0.0" -copy-webpack-plugin@^6.4.1: - version "6.4.1" - resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-6.4.1.tgz#138cd9b436dbca0a6d071720d5414848992ec47e" - integrity sha512-MXyPCjdPVx5iiWyl40Va3JGh27bKzOTNY3NjUTrosD2q7dR/cLD0013uqJ3BpFbUjyONINjb6qI7nDIJujrMbA== - dependencies: - cacache "^15.0.5" - fast-glob "^3.2.4" - find-cache-dir "^3.3.1" - glob-parent "^5.1.1" - globby "^11.0.1" - loader-utils "^2.0.0" - normalize-path "^3.0.0" - p-limit "^3.0.2" - schema-utils "^3.0.0" - serialize-javascript "^5.0.1" - webpack-sources "^1.4.3" - core-js-compat@^3.25.1: version "3.47.0" resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.47.0.tgz#698224bbdbb6f2e3f39decdda4147b161e3772a3" @@ -6332,7 +6275,7 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-glob@^3.2.11, fast-glob@^3.2.4, fast-glob@^3.2.9, fast-glob@^3.3.0: +fast-glob@^3.2.11, fast-glob@^3.2.9, fast-glob@^3.3.0: version "3.3.3" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818" integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== @@ -6466,7 +6409,7 @@ finalhandler@~1.3.1: statuses "~2.0.2" unpipe "~1.0.0" -find-cache-dir@^3.3.1, find-cache-dir@^3.3.2: +find-cache-dir@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b" integrity sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig== @@ -6754,7 +6697,7 @@ getpass@^0.1.1: dependencies: assert-plus "^1.0.0" -glob-parent@^5.1.1, glob-parent@^5.1.2, glob-parent@~5.1.2: +glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== @@ -6830,7 +6773,7 @@ globalthis@^1.0.4: define-properties "^1.2.1" gopd "^1.0.1" -globby@^11.0.1, globby@^11.1.0: +globby@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== @@ -8826,7 +8769,7 @@ minipass-json-stream@^1.0.1: jsonparse "^1.3.1" minipass "^3.0.0" -minipass-pipeline@^1.2.2, minipass-pipeline@^1.2.4: +minipass-pipeline@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c" integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A== @@ -11123,13 +11066,6 @@ send@~0.19.0: range-parser "~1.2.1" statuses "2.0.1" -serialize-javascript@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-5.0.1.tgz#7886ec848049a462467a97d3d918ebb2aaf934f4" - integrity sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA== - dependencies: - randombytes "^2.1.0" - serialize-javascript@^6.0.0, serialize-javascript@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" @@ -11426,11 +11362,6 @@ sortablejs@1.15.6: resolved "https://registry.yarnpkg.com/sortablejs/-/sortablejs-1.15.6.tgz#ff93699493f5b8ab8d828f933227b4988df1d393" integrity sha512-aNfiuwMEpfBM/CN6LY0ibyhxPfPbyFeBTYJKCvzkJ2GkUpazIt3H+QIPAMHwqQ7tMKaHz1Qj+rJJCqljnf4p3A== -source-list-map@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" - integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== - "source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.2, source-map-js@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" @@ -11558,13 +11489,6 @@ ssri@^10.0.0: dependencies: minipass "^7.0.3" -ssri@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af" - integrity sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ== - dependencies: - minipass "^3.1.1" - ssri@^9.0.0: version "9.0.1" resolved "https://registry.yarnpkg.com/ssri/-/ssri-9.0.1.tgz#544d4c357a8d7b71a19700074b6883fcb4eae057" @@ -11622,16 +11546,7 @@ streamroller@^3.1.5: debug "^4.3.4" fs-extra "^8.1.0" -"string-width-cjs@npm:string-width@^4.2.0": - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -11695,7 +11610,7 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -11709,13 +11624,6 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - strip-ansi@^7.0.1: version "7.1.2" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.2.tgz#132875abde678c7ea8d691533f2e7e22bb744dba" @@ -11786,7 +11694,7 @@ tapable@^2.1.1, tapable@^2.2.0: resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.3.0.tgz#7e3ea6d5ca31ba8e078b560f0d83ce9a14aa8be6" integrity sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg== -tar@^6.0.2, tar@^6.1.11, tar@^6.1.2: +tar@^6.1.11, tar@^6.1.2: version "6.2.1" resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== @@ -12246,13 +12154,6 @@ unicode-property-aliases-ecmascript@^2.0.0: resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz#301d4f8a43d2b75c97adfad87c9dd5350c9475d1" integrity sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ== -unique-filename@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" - integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== - dependencies: - unique-slug "^2.0.0" - unique-filename@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-2.0.1.tgz#e785f8675a9a7589e0ac77e0b5c34d2eaeac6da2" @@ -12267,13 +12168,6 @@ unique-filename@^3.0.0: dependencies: unique-slug "^4.0.0" -unique-slug@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" - integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== - dependencies: - imurmurhash "^0.1.4" - unique-slug@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-3.0.0.tgz#6d347cf57c8a7a7a6044aabd0e2d74e4d76dc7c9" @@ -12611,14 +12505,6 @@ webpack-merge@^5.10.0, webpack-merge@^5.7.3: flat "^5.0.2" wildcard "^2.0.0" -webpack-sources@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" - integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== - dependencies: - source-list-map "^2.0.0" - source-map "~0.6.1" - webpack-sources@^3.0.0, webpack-sources@^3.2.3: version "3.3.3" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.3.3.tgz#d4bf7f9909675d7a070ff14d0ef2a4f3c982c723" @@ -12820,7 +12706,7 @@ word-wrap@^1.2.5: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -12838,15 +12724,6 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"