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..ccae3f38613 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,245 @@ +# 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.x at http://127.0.0.1:8087/server (~2-4 min first run). The image set is +# recognised automatically (read from the compose files) and the script prints + validates the +# running version/flavor after boot. Two flavors: +build-scripts/run/dev.backend.sh # upstream public demo (default): right version, public content +FLAVOR=clarin build-scripts/run/dev.backend.sh fresh # the CORRECT CLARIN backend (dataquest) + CLARIN content +# ('fresh' wipes volumes — required when switching flavor, since -loadsql only loads an empty DB) + +# 2) FRONTEND: live-reload dev server on http://localhost:4000 +yarn start:dev:local +``` + +`dev.backend.sh` brings the backend up (IPv4 host, CORS derived from `UI_PORT`, sample dataset), +reindexes Solr, then **recognises the running backend** and warns if its version/flavor won't match +this FE; `start:dev:local` is `ng serve` with the right `DSPACE_REST_*` env baked in. +Stop/wipe with `docker compose -f docker/docker-compose-rest.yml -f docker/db.entities.yml down -v` +(swap in `-f docker/db.clarin.yml` for the CLARIN flavor). + +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). + +### Backend image — recognised automatically (don't hardcode it) + +`dev.backend.sh` does **not** hard-code the backend image. It **reads the image tags from the repo's +own compose files** (the source of truth), selects a set by `FLAVOR`, and after boot recognises the +running backend — printing its image, version, flavor, and a browse-definitions canary (the DSpace-7.5 +mismatch trap). The image the compose file declares as its *default* is deliberately **not** the one to +run as-is: + +| Source (in the code) | REST image | Flavor | Version | +|---|---|---|---| +| `docker/docker-compose-rest.yml:70` (compose default) | `dataquest/dspace:dtq-dev-7.5` | CLARIN | **7.5 — breaks browse-defs vs this 7.6.x FE** | +| `docker/docker-compose-ci.yml:38` (what CI validates) | `dataquest/dspace:dspace-7_x-test` | CLARIN | 7.6.x ✅ | +| `dev.backend.sh` `FLAVOR=upstream` (default) | `dspace/dspace:dspace-7_x` | upstream demo | 7.6.x ✅ | + +So `FLAVOR=clarin` reads the **CI** default (version-correct CLARIN), *not* the rest.yml default; +`FLAVOR=upstream` (default) keeps the instant public-demo path. The post-boot recogniser prints: + +``` + Backend recognised: + image : dspace/dspace:dspace-7_x + version : DSpace 7.6.7-SNAPSHOT (this FE is 7.6.5) + flavor : upstream demo (CLARIN endpoints/content ABSENT) + browse-definitions canary : HTTP 200 (OK) + note: for the CORRECT CLARIN backend (CLARIN endpoints + content) run: + FLAVOR=clarin build-scripts/run/dev.backend.sh fresh +``` + +(`FLAVOR=clarin` uses `docker/db.clarin.yml`, the CLARIN counterpart of `db.entities.yml`: a `-loadsql` +Postgres fed the dataquest CLARIN test dump — same image + dump that CI validates. First run pulls +~1-2 GB of dataquest images.) + +`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 — now auto-checked.** The FE is **7.6.x**, so use a **7.6.x** BE. + The `dataquest/dspace:dtq-dev-7.5` image (the compose *default*, see "Backend image — recognised + automatically") is **DSpace 7.5** and causes `An error occurred while retrieving the browse + definitions` in the console. `dev.backend.sh` now handles this for you: it picks a 7.6.x image by + `FLAVOR` and runs a browse-definitions canary after boot, warning loudly if a 7.5-style BE is + detected. For CLARIN fidelity use `FLAVOR=clarin` (the version-correct `dataquest/dspace:dspace-7_x-test`). + +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..06e0da06c79 --- /dev/null +++ b/build-scripts/run/dev.backend.sh @@ -0,0 +1,144 @@ +#!/usr/bin/env bash +# +# One-command local-dev BACKEND for working on the native frontend. +# +# Brings up a DSpace backend in Docker (matching this FE), loaded with a sample dataset, reachable at +# http://127.0.0.1:8087/server, then indexes Solr so browse/search/"What's New" populate. After it +# prints "Backend ready", start the FE: +# +# yarn start:dev:local # ng serve, live-reload, http://localhost:4000 (needs Node 18 — see .nvmrc) +# +# The backend IMAGE is recognised AUTOMATICALLY rather than hardcoded here: +# * image tags are read from the repo's own compose files (the source of truth, so they can't go +# stale against a copy in this script), and +# * after boot the script recognises the running backend's version + flavor and warns if it does +# not match this FE (the DSpace-7.5 "browse definitions" trap). +# +# FLAVOR selects WHICH backend (override: FLAVOR=clarin ...): +# upstream (default) public DSpace demo — DSpace 7.6.x + the official demo dataset (db.entities.yml). +# Right VERSION for this FE and zero dataquest pull, but UPSTREAM flavor: CLARIN-specific +# endpoints/config/content are absent (some FE calls 404 — harmless to render). +# clarin the version-correct CLARIN/dataquest backend — the image DSpace CI validates +# (dataquest/dspace:dspace-7_x-test, read from docker/docker-compose-ci.yml) + the CLARIN +# test dataset (docker/db.clarin.yml). This is the "correct backend" for CLARIN feature +# work. NOTE: first run pulls ~1-2 GB of dataquest images. +# +# Usage: +# build-scripts/run/dev.backend.sh # up (reuses existing containers/data) +# build-scripts/run/dev.backend.sh fresh # wipe DB/Solr volumes first (REQUIRED to switch FLAVOR) +# FLAVOR=clarin build-scripts/run/dev.backend.sh fresh +# +# Notes: +# - 127.0.0.1 (not localhost): Node resolves localhost to IPv6 ::1, but the BE binds IPv4 only. +# - -loadsql images import only into an EMPTY pgdata volume, so always `fresh` when switching FLAVOR. +# +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" +# FE dev-server port; CORS is derived from it so the two can never drift (set UI_PORT to change both). +export UI_PORT="${UI_PORT:-4000}" +export UI_URL="http://localhost:${UI_PORT}" +export HOST_IP=127.0.0.1 +export DSPACE_SUBNET_PREFIX="10.10${INSTANCE}" +export REST_CORS_ALLOWED_ORIGINS="http://localhost:${UI_PORT},http://127.0.0.1:${UI_PORT}" +export DSPACE_VER="${DSPACE_VER:-dspace-7_x}" +export DOCKER_REGISTRY="${DOCKER_REGISTRY:-docker.io}" + +REST_YML=docker/docker-compose-rest.yml +CI_YML=docker/docker-compose-ci.yml +REST="http://127.0.0.1:808${INSTANCE}/server/api" + +# Read the default value of a compose `${VAR:-default}` straight from the file (source of truth). +compose_default() { grep -oE "\\\$\\{$1:-[^}]+\\}" "$2" | head -1 | sed -E 's/^.*:-//; s/}$//'; } + +# --- recognise WHICH backend image to use (by FLAVOR); tags come FROM THE REPO, not hardcoded here --- +FLAVOR="${FLAVOR:-upstream}" +if [ "$FLAVOR" = "clarin" ]; then + # Version-correct CLARIN REST image = the default DSpace CI runs against (docker-compose-ci.yml). + # Deliberately NOT the rest.yml default (dataquest/dspace:dtq-dev-7.5 is DSpace 7.5, which breaks + # browse-definitions against this 7.6.x FE — see the recognise step below and AGENTS.md Gotcha #6). + export DSPACE_REST_IMAGE="${DSPACE_REST_IMAGE:-$(compose_default DSPACE_CI_IMAGE "$CI_YML")}" + export DSPACE_SOLR_IMAGE="${DSPACE_SOLR_IMAGE:-$(compose_default DSPACE_SOLR_IMAGE "$REST_YML")}" + export DOCKER_OWNER="${DOCKER_OWNER:-dataquest}" + COMPOSE=(docker compose -f "$REST_YML" -f docker/db.clarin.yml) +else + # Upstream public demo: right version family (7.6.x) + the official demo dataset (db.entities.yml). + export DSPACE_REST_IMAGE="${DSPACE_REST_IMAGE:-dspace/dspace:dspace-7_x}" + export DSPACE_SOLR_IMAGE="${DSPACE_SOLR_IMAGE:-dspace/dspace-solr:dspace-7_x}" + export DOCKER_OWNER="${DOCKER_OWNER:-dspace}" + COMPOSE=(docker compose -f "$REST_YML" -f docker/db.entities.yml) +fi +echo ">> FLAVOR=${FLAVOR} DSPACE_REST_IMAGE=${DSPACE_REST_IMAGE}" + +# Recognise the RUNNING backend (whoever/whatever started it) and warn if it won't match this FE. +recognise_backend() { + local img ver fe browse flavor compat + img="$(docker inspect "dspace${INSTANCE}" --format '{{.Config.Image}}' 2>/dev/null || true)" + ver="$(curl -s "$REST" | sed -nE 's/.*"dspaceVersion" *: *"([^"]+)".*/\1/p' | head -1)" + fe="$(sed -nE 's/.*"version": *"([0-9][^"]*)".*/\1/p' package.json | head -1)" + browse="$(curl -s -o /dev/null -w '%{http_code}' "$REST/discover/browses" 2>/dev/null)" + case "$img" in + dataquest/*) flavor="CLARIN (dataquest)";; + dspace/*) flavor="upstream demo (CLARIN endpoints/content ABSENT)";; + *) flavor="unknown (${img:-?})";; + esac + [ "$browse" = "200" ] && compat="OK" || compat="MISMATCH — looks like a DSpace 7.5 backend" + echo "------------------------------------------------------------------" + echo " Backend recognised:" + echo " image : ${img:-?}" + echo " version : ${ver:-?} (this FE is ${fe:-7.6.x})" + echo " flavor : ${flavor}" + echo " browse-definitions canary : HTTP ${browse} (${compat})" + case "$ver" in + 'DSpace 7.6'*|'DSpace 7.7'*|'DSpace 8'*) ;; + *) echo " !! BE version may not match the FE; if the canary is not 200, use a 7.6.x image." >&2;; + esac + if [ "$FLAVOR" != "clarin" ] && [ "${img#dspace/}" != "$img" ]; then + echo " note: for the CORRECT CLARIN backend (CLARIN endpoints + content) run:" + echo " FLAVOR=clarin $0 fresh" + fi + echo "------------------------------------------------------------------" +} + +if [ "${1:-}" = "fresh" ]; then + echo ">> wiping previous dev backend (down -v)" + "${COMPOSE[@]}" down -v --remove-orphans || true +fi + +echo ">> starting backend (project ${COMPOSE_PROJECT_NAME}, flavor ${FLAVOR})" +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)" + +recognise_backend + +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/db.clarin.yml b/docker/db.clarin.yml new file mode 100644 index 00000000000..1677c6fea4f --- /dev/null +++ b/docker/db.clarin.yml @@ -0,0 +1,34 @@ +# +# CLARIN/dataquest content layer for LOCAL DEV. +# Used by build-scripts/run/dev.backend.sh when FLAVOR=clarin. +# +# This is the CLARIN counterpart of docker/db.entities.yml: instead of the upstream demo dataset it +# loads the dataquest CLARIN test database dump, and it skips the upstream Entities-specific +# item-submission tweaks. The image + dump are the same ones DSpace CI validates +# (see docker/docker-compose-ci.yml: DSPACE_CI_IMAGE / LOADSQL). +# +# Layer it on top of docker-compose-rest.yml: +# docker compose -f docker/docker-compose-rest.yml -f docker/db.clarin.yml up -d +# +# IMPORTANT: a -loadsql image only imports into an EMPTY pgdata volume, so switch flavors clean: +# FLAVOR=clarin build-scripts/run/dev.backend.sh fresh +# +services: + dspacedb: + # Upstream "loadsql" loader image (already pulled for the demo path). The loader flavor is + # irrelevant — the CONTENT is CLARIN, fetched from ${LOADSQL} on first boot. + image: ${DOCKER_REGISTRY:-docker.io}/dspace/dspace-postgres-pgcrypto:${DSPACE_VER:-dspace-7_x}-loadsql + environment: + # dataquest CLARIN test DB dump. Keep in sync with docker/docker-compose-ci.yml. + - LOADSQL=${LOADSQL:-https://github.com/dataquest-dev/DSpace/releases/download/data/dspace-test-database-dump_29.1.2024.sql} + dspace: + ### OVERRIDE the default 'entrypoint' from docker-compose-rest.yml ### + # 1. wait until Postgres is reachable, 2. migrate (ignored = tolerate out-of-order CLARIN + # migrations), 3. start Tomcat. dev.backend.sh runs `index-discovery -b` once the API is up. + entrypoint: + - /bin/bash + - '-c' + - | + while (! /dev/null 2>&1; do sleep 1; done; + /dspace/bin/dspace database migrate ignored + catalina.sh run 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"