diff --git a/.gitignore b/.gitignore index e4365f1e..1d467898 100644 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,6 @@ ui/.pnp.loader.mjs !ui/.yarn/plugins !ui/.yarn/releases !ui/.yarn/sdks -!ui/.yarn/versions \ No newline at end of file +!ui/.yarn/versions +api/static/ +api/beat.pid diff --git a/.gitpod.yml b/.gitpod.yml index 63073c75..80818c73 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -3,3 +3,12 @@ vscode: extensions: - ms-python.python - Vue.volar + +ports: + - port: 3000 + visibility: public + - port: 5050 + visibility: public + - port: 8000 + visibility: public + onOpen: open-browser \ No newline at end of file diff --git a/README.md b/README.md index 7c719c75..00c17021 100644 --- a/README.md +++ b/README.md @@ -30,10 +30,59 @@ username: admin password: foliom4n ``` +This will build the container images for backend, frontend and all dependent services +and may take quite a while to finish. +--- -This will build the container images for backend, frontend and all dependent services -and may take quite a while to finish. +### Running Locally (Minimal Docker Setup) + +If you want to run the application locally with minimal Docker usage (only loading timedb and cache services in Docker), follow these steps: + +#### Step 1: Start Local Environment + +**On Windows:** +```bash +run-local.bat +``` + +**On Linux/Mac:** +```bash +./run-local.sh +``` + +This will: +1. Start only the required Docker containers (timedb, cache, and pgadmin) +2. Set up a Python virtual environment +3. Install all Python dependencies +4. Configure the Django environment to connect to your local Docker containers +5. Run database migrations +6. Start the Django API server +7. Install Node.js dependencies for the UI +8. Start the UI development server + +#### Step 2: Start Celery for Background Tasks (Optional) + +**On Windows:** +```bash +run-celery-local.bat +``` + +This will start Celery worker and beat scheduler processes for background tasks. + +#### Step 3: Access Your Application + +Once everything is running, you can access: +- API: http://localhost:8000 +- UI: http://localhost:3000 +- PGAdmin: http://localhost:5050 (login: pgadmin4@pgadmin.org / admin) + +#### Step 4: Shutting Down + +Stop the Django and UI processes, then stop the Docker containers: +```bash +docker-compose -f docker-compose.local.yml down +``` ## Features diff --git a/api/.env.local b/api/.env.local new file mode 100644 index 00000000..76fd44d7 --- /dev/null +++ b/api/.env.local @@ -0,0 +1,7 @@ +DEBUG=on +SECRET_KEY='%k8!x4pm=mf!iqz^jws)ijn=)-md-uf_i=^mya1t*d!4f#^74k' +DATABASE_URL=psql://postgres:foliop4sswd@localhost:15432/folioman +CACHE_URL=rediscache://localhost:16379/1?client_class=django_redis.client.DefaultClient&timeout=86400 +CELERY_BROKER_URL=redis://localhost:16379/3 +CELERY_RESULT_BACKEND=redis://localhost:16379/5 +ENVIRONMENT="dev" diff --git a/api/mutualfunds/models.py b/api/mutualfunds/models.py index 0fc85831..25deeb4e 100644 --- a/api/mutualfunds/models.py +++ b/api/mutualfunds/models.py @@ -93,7 +93,9 @@ class Portfolio(models.Model): pan = models.CharField(max_length=10, null=True, blank=True) class Meta: - unique_together = ("user_id", "name") + constraints = [ + models.UniqueConstraint(fields=['user_id', 'name'], name='unique_user_name') + ] def __str__(self): return self.name @@ -103,7 +105,7 @@ class Folio(models.Model): """Mutual Fund Folio""" amc = models.ForeignKey(AMC, models.PROTECT) - portfolio = models.ForeignKey(Portfolio, models.CASCADE, related_name="folios") + portfolio = models.ForeignKey(Portfolio, on_delete=models.CASCADE, related_name="folios") number = models.CharField(max_length=128, unique=True) pan = models.CharField(max_length=10, null=True, blank=True) kyc = models.BooleanField(default=False) diff --git a/api/mutualfunds/tests.py b/api/mutualfunds/tests.py index 1257b7c9..62fbaf5d 100644 --- a/api/mutualfunds/tests.py +++ b/api/mutualfunds/tests.py @@ -1,7 +1,10 @@ +from decimal import Decimal from django.test import TestCase +from tablib import Dataset from mutualfunds.importers.cas import import_cas -from mutualfunds.models import Portfolio, Folio +from mutualfunds.importers.master import FundSchemeResource +from mutualfunds.models import Portfolio, Folio, FundScheme class TestImportCas(TestCase): @@ -21,17 +24,25 @@ def test_import_cas_valid_email_name(self): result = import_cas(self.data, self.user_id) self.assertIsNotNone(result) + # Additional assertions + portfolio = Portfolio.objects.get(email="test@example.com") + self.assertEqual(portfolio.name, "Test User") + self.assertEqual(portfolio.user_id, self.user_id) + def test_import_cas_invalid_email(self): # Test case for invalid email self.data["investor_info"]["email"] = "" with self.assertRaises(ValueError): import_cas(self.data, self.user_id) + # Additional assertions + self.assertFalse(Portfolio.objects.filter(email="").exists()) + def test_import_cas_new_folio_creation(self): # Test case for creating a new folio self.data["folios"] = [{ "folio": "123", - "KYC" : "OK", + "KYC": "OK", "PANKYC": "OK", "PAN": "ABCDE1234F", "schemes": [{ @@ -61,8 +72,30 @@ def test_import_cas_new_folio_creation(self): import_cas(self.data, self.user_id) self.assertEqual(Folio.objects.count(), 1) + # Additional assertions + folio = Folio.objects.get(number="123") + self.assertTrue(folio.kyc) + self.assertTrue(folio.pan_kyc) + self.assertEqual(folio.pan, "ABCDE1234F") + + # Additional assertions for transactions and schemes + schemes = folio.schemes.all() + self.assertEqual(schemes.count(), 1) + + scheme = schemes.first() + self.assertEqual(scheme.scheme_id, FundScheme.objects.get(isin="INF846K01EW2").id) + + transactions = scheme.transactions.all() + self.assertEqual(transactions.count(), 1) + + transaction = transactions.first() + self.assertEqual(transaction.amount, Decimal('1000.0')) + self.assertEqual(transaction.balance, Decimal('23.711')) + self.assertEqual(transaction.nav, Decimal('42.1747')) + self.assertEqual(transaction.units, Decimal('23.711')) + self.assertEqual(transaction.description, "Purchase") def test_import_cas_missing_kyc(self): - # Test case for creating a new folio + # Test case for missing KYC self.data["folios"] = [{ "folio": "124", "PANKYC": "OK", @@ -95,4 +128,23 @@ def test_import_cas_missing_kyc(self): import_cas(self.data, self.user_id) self.assertEqual(Folio.objects.count(), 1) + +class TestDependencies(TestCase): + + def test_import_export(self): + # Test django-import-export functionality + resource = FundSchemeResource() + dataset = Dataset(headers=["sid", "name", "rta", "plan", "rta_code", "amc_code", "amfi_code", "isin", "start_date", "end_date", "amc_id", "category_id"]) + dataset.append([1, "Test Scheme", "Test RTA", "DIRECT", "123", "456", "789", "INF123456789", "2025-01-01", "2025-12-31", 1, 1]) + result = resource.import_data(dataset, dry_run=True) + self.assertFalse(result.has_errors(), "Import should not have errors") + + def test_tablib(self): + # Test tablib[pandas] functionality + dataset = Dataset(headers=["Name", "Age"]) + dataset.headers = ["Name", "Age"] + dataset.append(["Alice", 30]) + dataset.append(["Bob", 25]) + self.assertEqual(len(dataset), 2, "Dataset should have 2 rows") + # Additional test cases can be added here to cover other functionalities diff --git a/api/requirements.txt b/api/requirements.txt index a74da6e0..d65b7673 100644 --- a/api/requirements.txt +++ b/api/requirements.txt @@ -1,6 +1,6 @@ casparser[mupdf]==0.5.5 celery==5.4.0 -Django==5.1.5 +Django==5.1.13 django-celery-beat==2.7.0 django-celery-results==2.5.1 django-click>=2.3.0 @@ -8,8 +8,8 @@ django-environ==0.11.2 django-import-export==2.9.0 django-redis==5.4.0 djangorestframework==3.15.2 -djangorestframework-simplejwt==5.3.1 -gunicorn==22.0.0 +djangorestframework-simplejwt==5.5.1 +gunicorn==23.0.0 lxml numpy pandas @@ -17,7 +17,7 @@ psycopg2 python-dateutil>=2.8.1 pytz>=2021.1 redis==5.2.1 -requests==2.32.3 +requests==2.32.4 sentry-sdk==2.19.2 tablib[pandas]==3.3.0 xirr==0.1.8 diff --git a/api/settings.py b/api/settings.py index cb113c82..91a34d54 100644 --- a/api/settings.py +++ b/api/settings.py @@ -11,6 +11,7 @@ """ import datetime +import os from pathlib import Path import click.exceptions @@ -22,7 +23,12 @@ # set casting, default value DEBUG=(bool, False) ) -environ.Env.read_env() + +# Ensure the .env file is loaded +BASE_DIR = Path(__file__).resolve().parent +ENV_FILE = BASE_DIR / '.env' +if ENV_FILE.exists(): + environ.Env.read_env(str(ENV_FILE)) # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent diff --git a/docker-compose.local.yml b/docker-compose.local.yml new file mode 100644 index 00000000..759012a9 --- /dev/null +++ b/docker-compose.local.yml @@ -0,0 +1,37 @@ + +services: + timedb: + image: timescale/timescaledb:latest-pg17 + restart: unless-stopped + volumes: + - folioman-db:/var/lib/postgresql/data + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: foliop4sswd + POSTGRES_DB: folioman + ports: + - "127.0.0.1:15432:5432" + cache: + image: redis:alpine + command: [ "redis-server", "--appendonly", "yes" ] + volumes: + - folioman-cache:/data + ports: + - "127.0.0.1:16379:6379" + pgadmin: + image: dpage/pgadmin4 + extra_hosts: [ 'host.docker.internal:host-gateway' ] + environment: + - PGADMIN_DEFAULT_EMAIL=pgadmin4@pgadmin.org + - PGADMIN_DEFAULT_PASSWORD=admin + - PGADMIN_CONFIG_SERVER_MODE=False + - PGADMIN_CONFIG_MASTER_PASSWORD_REQUIRED=False + ports: + - "5050:80" + depends_on: + - timedb + +volumes: + folioman-db: + folioman-cache: + \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 9dd9e740..428b6b44 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,3 @@ -version: '3.4' x-app: &default-app #image: backend-image:latest @@ -30,7 +29,7 @@ x-celery: &celery-app services: timedb: - image: timescale/timescaledb:latest-pg16 + image: timescale/timescaledb:latest-pg17 restart: unless-stopped volumes: - folioman-db:/var/lib/postgresql/data @@ -54,7 +53,7 @@ services: - ./ui:/home/node/ui - folioman-ui-node-modules:/home/node/ui/node_modules working_dir: /home/node/ui - command: sh -c "yarn install && npm run build && npm run start" + command: sh -c "yarn install && yarn run build && yarn run start" api: build: ./api command: bash -c "/wait && diff --git a/run-celery-local.bat b/run-celery-local.bat new file mode 100755 index 00000000..6549101f --- /dev/null +++ b/run-celery-local.bat @@ -0,0 +1,37 @@ +@echo off +REM Script to run Celery locally with minimal Docker usage on Windows + +REM Make sure Redis is running +echo Checking if Redis is running... +docker-compose -f docker-compose.local.yml ps | findstr "cache" | findstr "Up" >nul +if errorlevel 1 ( + echo Redis is not running. Starting required Docker services... + docker-compose -f docker-compose.local.yml up -d cache + timeout /t 5 +) + +REM Activate virtual environment +call .venv\Scripts\activate.bat + +cd api + +REM Check if .env exists (should have been created by run-local.bat) +if not exist .env ( + echo Setting up local environment file... + copy .env.local .env +) + +REM Start Celery beat +echo Starting Celery beat... +start "Celery Beat" celery -A taskman beat -l INFO --pidfile=./beat.pid + +REM Start Celery worker +echo Starting Celery worker... +start "Celery Worker" celery -A taskman worker -l INFO + +echo ================================================ +echo Celery services are now running +echo ================================================ +echo Press Ctrl+C in each terminal window to stop the services + +cmd /k \ No newline at end of file diff --git a/run-celery-local.sh b/run-celery-local.sh new file mode 100755 index 00000000..c724be93 --- /dev/null +++ b/run-celery-local.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# Script to run Celery locally with minimal Docker usage on Linux/macOS + +# Make sure Redis is running +echo "Checking if Redis is running..." +if ! docker-compose -f docker-compose.local.yml ps | grep -q "cache.*Up"; then + echo "Redis is not running. Starting required Docker services..." + docker-compose -f docker-compose.local.yml up -d cache + sleep 5 +fi + +# Activate virtual environment from .venv folder instead of venv +source .venv/bin/activate + +cd api || { echo "Error: Cannot change to api directory"; exit 1; } + +# Check if .env exists (should have been created by run-local.sh) +if [ ! -f .env ]; then + echo "Setting up local environment file..." + cp .env.local .env +fi + +# Start Celery beat in background +echo "Starting Celery beat..." +celery -A taskman beat -l INFO --pidfile=./beat.pid --detach + +# Start Celery worker in background +echo "Starting Celery worker..." +celery -A taskman worker -l INFO --detach + +echo "================================================" +echo "Celery services are now running" +echo "================================================" +echo "Run 'pkill -f celery' to stop all Celery processes" + +# Keep terminal open +exec $SHELL diff --git a/run-local.bat b/run-local.bat new file mode 100644 index 00000000..89b60e43 --- /dev/null +++ b/run-local.bat @@ -0,0 +1,64 @@ +@echo off +REM Script to run FolioMan locally with minimal Docker usage on Windows + +echo Starting required Docker services (timedb, cache, pgadmin)... +docker-compose -f docker-compose.local.yml up -d + +echo Waiting for services to be ready... +timeout /t 5 + +REM Set up Python environment +if not exist .venv ( + echo Creating Python virtual environment... + python -m venv .venv +) + +REM Activate virtual environment +call .venv\Scripts\activate.bat + +REM Install Python requirements +echo Installing Python requirements... +cd api +pip install -r requirements.txt +pip install casparser-isin + +REM Use the local environment file +if not exist .env ( + echo Setting up local environment file... + copy .env.local .env +) + +REM Run Django migrations +echo Running database migrations... +python manage.py migrate + +REM Collect static files +echo Collecting static files... +python manage.py collectstatic --noinput + +REM Start Django server +echo Starting Django server... +start "Django Server" python manage.py runserver 8000 + +REM Setup UI +echo Setting up UI... +cd ..\ui + +REM Install Node.js dependencies +echo Installing Node.js dependencies... +call yarn install + +REM Build and start UI +echo Building and starting UI... +start "UI Server" yarn run dev --host 0.0.0.0 + +echo ================================================ +echo FolioMan is now running: +echo API: http://localhost:8000/admin +echo UI: http://localhost:3000 +echo PGAdmin: http://localhost:5050 +echo ================================================ +echo Press Ctrl+C in each terminal window to stop the servers +echo Run 'docker-compose -f docker-compose.local.yml down' to stop Docker services when done + +cmd /k diff --git a/run-local.sh b/run-local.sh new file mode 100755 index 00000000..30f1e995 --- /dev/null +++ b/run-local.sh @@ -0,0 +1,77 @@ +#!/bin/bash +# Script to run FolioMan locally with minimal Docker usage + +# Start Docker services (timedb, cache, pgadmin) +echo "Starting required Docker services (timedb, cache, pgadmin)..." +docker-compose -f docker-compose.local.yml up -d + +echo "Waiting for services to be ready..." +sleep 5 + +# Set up Python environment +if [ ! -d ".venv" ]; then + echo "Creating Python virtual environment..." + python -m venv .venv +fi + +# Activate virtual environment +source .venv/bin/activate || source .venv/Scripts/activate + +# Install Python requirements +echo "Installing Python requirements..." +cd api || { echo "Error: api directory not found"; exit 1; } +pip install -r requirements.txt +pip install casparser-isin + +# Use the local environment file +if [ ! -f ".env" ] || [ ! -L ".env" ]; then + echo "Setting up local environment file..." + cp .env.local .env +fi + +# Run Django migrations +echo "Running database migrations..." +python manage.py migrate + +# Collect static files +echo "Collecting static files..." +python manage.py collectstatic --noinput + +# Start Django server in background +echo "Starting Django server..." +python manage.py runserver 8000 & +API_PID=$! + +# Setup UI +echo "Setting up UI..." +cd ../ui || { echo "Error: ui directory not found"; exit 1; } + +# Install Node.js dependencies +echo "Installing Node.js dependencies..." +yarn install + +# Build and start UI +echo "Building and starting UI..." +# Modified to explicitly set the host to 0.0.0.0 to make it accessible from outside +yarn run dev --host 0.0.0.0 & +UI_PID=$! + +echo "================================================" +echo "FolioMan is now running:" +echo "API: http://localhost:8000/admin" +echo "UI: http://localhost:3000" +echo "PGAdmin: http://localhost:5050" +echo "================================================" +echo "Press Ctrl+C to stop all services" + +# Handle graceful shutdown +function cleanup { + echo "Shutting down services..." + kill $API_PID + kill $UI_PID + cd $(dirname "$0") && docker-compose -f docker-compose.local.yml down + exit 0 +} + +trap cleanup INT TERM +wait \ No newline at end of file diff --git a/ui/yarn.lock b/ui/yarn.lock index 926365df..63e518c5 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -61,6 +61,17 @@ __metadata: languageName: node linkType: hard +"@babel/code-frame@npm:^7.26.2": + version: 7.26.2 + resolution: "@babel/code-frame@npm:7.26.2" + dependencies: + "@babel/helper-validator-identifier": ^7.25.9 + js-tokens: ^4.0.0 + picocolors: ^1.0.0 + checksum: db13f5c42d54b76c1480916485e6900748bbcb0014a8aca87f50a091f70ff4e0d0a6db63cade75eb41fcc3d2b6ba0a7f89e343def4f96f00269b41b8ab8dd7b8 + languageName: node + linkType: hard + "@babel/compat-data@npm:^7.13.11, @babel/compat-data@npm:^7.14.0, @babel/compat-data@npm:^7.15.0": version: 7.15.0 resolution: "@babel/compat-data@npm:7.15.0" @@ -598,6 +609,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-string-parser@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-string-parser@npm:7.25.9" + checksum: 6435ee0849e101681c1849868278b5aee82686ba2c1e27280e5e8aca6233af6810d39f8e4e693d2f2a44a3728a6ccfd66f72d71826a94105b86b731697cdfa99 + languageName: node + linkType: hard + "@babel/helper-validator-identifier@npm:^7.14.5, @babel/helper-validator-identifier@npm:^7.14.9, @babel/helper-validator-identifier@npm:^7.15.7": version: 7.15.7 resolution: "@babel/helper-validator-identifier@npm:7.15.7" @@ -619,6 +637,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-identifier@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-validator-identifier@npm:7.25.9" + checksum: 5b85918cb1a92a7f3f508ea02699e8d2422fe17ea8e82acd445006c0ef7520fbf48e3dbcdaf7b0a1d571fc3a2715a29719e5226636cb6042e15fe6ed2a590944 + languageName: node + linkType: hard + "@babel/helper-validator-option@npm:^7.14.5": version: 7.14.5 resolution: "@babel/helper-validator-option@npm:7.14.5" @@ -645,36 +670,13 @@ __metadata: languageName: node linkType: hard -"@babel/helpers@npm:^7.15.4": - version: 7.15.4 - resolution: "@babel/helpers@npm:7.15.4" - dependencies: - "@babel/template": ^7.15.4 - "@babel/traverse": ^7.15.4 - "@babel/types": ^7.15.4 - checksum: e60738110086c183d0ce369ad56949d5dceeb7d73d8fdb892f36d5b8525192e6b97f4563eb77334f47ac27ac43a21f3c4cd53bff342c2a0d5f4008a2b0169c89 - languageName: node - linkType: hard - -"@babel/helpers@npm:^7.16.0": - version: 7.16.0 - resolution: "@babel/helpers@npm:7.16.0" - dependencies: - "@babel/template": ^7.16.0 - "@babel/traverse": ^7.16.0 - "@babel/types": ^7.16.0 - checksum: 88d37c414dfb8815d5966774f9d65c9378fe9fd2e7e70f5c1c13e0611eca41b7114e9ffa8b37a69682c1a31a83dc7302e92e759b515220fea16c8e642282375a - languageName: node - linkType: hard - -"@babel/helpers@npm:^7.24.5": - version: 7.24.5 - resolution: "@babel/helpers@npm:7.24.5" +"@babel/helpers@npm:^7.15.4, @babel/helpers@npm:^7.16.0, @babel/helpers@npm:^7.24.5": + version: 7.27.0 + resolution: "@babel/helpers@npm:7.27.0" dependencies: - "@babel/template": ^7.24.0 - "@babel/traverse": ^7.24.5 - "@babel/types": ^7.24.5 - checksum: 941937456ca50ef44dbc5cdcb9a74c6ce18ce38971663acd80b622e7ecf1cc4fa034597de3ccccc37939d324139f159709f493fd8e7c385adbc162cb0888cfee + "@babel/template": ^7.27.0 + "@babel/types": ^7.27.0 + checksum: d11bb8ada0c5c298d2dbd478d69b16a79216b812010e78855143e321807df4e34f60ab65e56332e72315ccfe52a22057f0cf1dcc06e518dcfa3e3141bb8576cd languageName: node linkType: hard @@ -739,6 +741,17 @@ __metadata: languageName: node linkType: hard +"@babel/parser@npm:^7.27.0": + version: 7.27.0 + resolution: "@babel/parser@npm:7.27.0" + dependencies: + "@babel/types": ^7.27.0 + bin: + parser: ./bin/babel-parser.js + checksum: 062a4e6d51553603253990c84e051ed48671a55b9d4e9caf2eff9dc888465070a0cfd288a467dbf0d99507781ea4a835b5606e32ddc0319f1b9273f913676829 + languageName: node + linkType: hard + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:^7.15.4": version: 7.15.4 resolution: "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:7.15.4" @@ -1620,11 +1633,11 @@ __metadata: linkType: hard "@babel/runtime@npm:^7.14.0, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.8.4": - version: 7.15.4 - resolution: "@babel/runtime@npm:7.15.4" + version: 7.26.10 + resolution: "@babel/runtime@npm:7.26.10" dependencies: - regenerator-runtime: ^0.13.4 - checksum: c40825430400e47c19b97e4142d5315d2910305b9714d44a711472587ee2fd4521fdba5f02ddd9df3902f5e988d9854fa83f4da1e0c091f70f6983fa52480606 + regenerator-runtime: ^0.14.0 + checksum: 22d2e0abb86e90de489ab16bb578db6fe2b63a88696db431198b24963749820c723f1982298cdbbea187f7b2b80fb4d98a514faf114ddb2fdc14a4b96277b955 languageName: node linkType: hard @@ -1668,6 +1681,17 @@ __metadata: languageName: node linkType: hard +"@babel/template@npm:^7.27.0": + version: 7.27.0 + resolution: "@babel/template@npm:7.27.0" + dependencies: + "@babel/code-frame": ^7.26.2 + "@babel/parser": ^7.27.0 + "@babel/types": ^7.27.0 + checksum: 46d6db4c204a092f11ad6c3bfb6ec3dc1422e32121186d68ab1b3e633313aa5b7e21f26ca801dbd7da21f256225305a76454429fc500e52dabadb30af35df961 + languageName: node + linkType: hard + "@babel/traverse@npm:^7.13.0, @babel/traverse@npm:^7.15.4, @babel/traverse@npm:^7.16.0, @babel/traverse@npm:^7.24.5": version: 7.24.5 resolution: "@babel/traverse@npm:7.24.5" @@ -1717,6 +1741,16 @@ __metadata: languageName: node linkType: hard +"@babel/types@npm:^7.27.0": + version: 7.27.0 + resolution: "@babel/types@npm:7.27.0" + dependencies: + "@babel/helper-string-parser": ^7.25.9 + "@babel/helper-validator-identifier": ^7.25.9 + checksum: 59582019eb8a693d4277015d4dec0233874d884b9019dcd09550332db7f0f2ac9e30eca685bb0ada4bab5a4dc8bbc2a6bcaadb151c69b7e6aa94b5eaf8fc8c51 + languageName: node + linkType: hard + "@babel/types@npm:^7.8.3": version: 7.18.13 resolution: "@babel/types@npm:7.18.13" @@ -4757,12 +4791,12 @@ __metadata: linkType: hard "brace-expansion@npm:^1.1.7": - version: 1.1.11 - resolution: "brace-expansion@npm:1.1.11" + version: 1.1.12 + resolution: "brace-expansion@npm:1.1.12" dependencies: balanced-match: ^1.0.0 concat-map: 0.0.1 - checksum: faf34a7bb0c3fcf4b59c7808bc5d2a96a40988addf2e7e09dfbb67a2251800e0d14cd2bfc1aa79174f2f5095c54ff27f46fb1289fe2d77dac755b5eb3434cc07 + checksum: 12cb6d6310629e3048cadb003e1aca4d8c9bb5c67c3c321bafdd7e7a50155de081f78ea3e0ed92ecc75a9015e784f301efc8132383132f4f7904ad1ac529c562 languageName: node linkType: hard @@ -5150,6 +5184,16 @@ __metadata: languageName: node linkType: hard +"call-bind-apply-helpers@npm:^1.0.0, call-bind-apply-helpers@npm:^1.0.1, call-bind-apply-helpers@npm:^1.0.2": + version: 1.0.2 + resolution: "call-bind-apply-helpers@npm:1.0.2" + dependencies: + es-errors: ^1.3.0 + function-bind: ^1.1.2 + checksum: b2863d74fcf2a6948221f65d95b91b4b2d90cfe8927650b506141e669f7d5de65cea191bf788838bc40d13846b7886c5bc5c84ab96c3adbcf88ad69a72fcdc6b + languageName: node + linkType: hard + "call-bind@npm:^1.0.0, call-bind@npm:^1.0.2": version: 1.0.2 resolution: "call-bind@npm:1.0.2" @@ -5173,6 +5217,28 @@ __metadata: languageName: node linkType: hard +"call-bind@npm:^1.0.8": + version: 1.0.8 + resolution: "call-bind@npm:1.0.8" + dependencies: + call-bind-apply-helpers: ^1.0.0 + es-define-property: ^1.0.0 + get-intrinsic: ^1.2.4 + set-function-length: ^1.2.2 + checksum: aa2899bce917a5392fd73bd32e71799c37c0b7ab454e0ed13af7f6727549091182aade8bbb7b55f304a5bc436d543241c14090fb8a3137e9875e23f444f4f5a9 + languageName: node + linkType: hard + +"call-bound@npm:^1.0.3, call-bound@npm:^1.0.4": + version: 1.0.4 + resolution: "call-bound@npm:1.0.4" + dependencies: + call-bind-apply-helpers: ^1.0.2 + get-intrinsic: ^1.3.0 + checksum: 2f6399488d1c272f56306ca60ff696575e2b7f31daf23bc11574798c84d9f2759dceb0cb1f471a85b77f28962a7ac6411f51d283ea2e45319009a19b6ccab3b2 + languageName: node + linkType: hard + "caller-callsite@npm:^2.0.0": version: 2.0.0 resolution: "caller-callsite@npm:2.0.0" @@ -5467,12 +5533,13 @@ __metadata: linkType: hard "cipher-base@npm:^1.0.0, cipher-base@npm:^1.0.1, cipher-base@npm:^1.0.3": - version: 1.0.4 - resolution: "cipher-base@npm:1.0.4" + version: 1.0.7 + resolution: "cipher-base@npm:1.0.7" dependencies: - inherits: ^2.0.1 - safe-buffer: ^5.0.1 - checksum: 47d3568dbc17431a339bad1fe7dff83ac0891be8206911ace3d3b818fc695f376df809bea406e759cdea07fff4b454fa25f1013e648851bec790c1d75763032e + inherits: ^2.0.4 + safe-buffer: ^5.2.1 + to-buffer: ^1.2.2 + checksum: 3c3b5ddd8c8bfbb68fdd134c4c6db408b57a81f19260c59a5e1f5b75cb67fc5a0127af2ffb84a14720c9d249226659544c593245123f42285c82267cf787b883 languageName: node linkType: hard @@ -5892,13 +5959,13 @@ __metadata: languageName: node linkType: hard -"cookies@npm:~0.8.0": - version: 0.8.0 - resolution: "cookies@npm:0.8.0" +"cookies@npm:~0.9.0": + version: 0.9.1 + resolution: "cookies@npm:0.9.1" dependencies: depd: ~2.0.0 keygrip: ~1.1.0 - checksum: 806055a44f128705265b1bc6a853058da18bf80dea3654ad99be20985b1fa1b14f86c1eef73644aab8071241f8a78acd57202b54c4c5c70769fc694fbb9c4edc + checksum: 213e4d14847b582fbd8a003203d3621a4b9fa792a315c37954e89332d38fac5bcc34ba92ef316ad6d5fe28f0187aaa115927fbbe2080744ad1707a93b4313247 languageName: node linkType: hard @@ -6020,7 +6087,7 @@ __metadata: languageName: node linkType: hard -"create-hash@npm:^1.1.0, create-hash@npm:^1.1.2, create-hash@npm:^1.2.0": +"create-hash@npm:^1.1.0, create-hash@npm:^1.2.0": version: 1.2.0 resolution: "create-hash@npm:1.2.0" dependencies: @@ -6033,7 +6100,19 @@ __metadata: languageName: node linkType: hard -"create-hmac@npm:^1.1.0, create-hmac@npm:^1.1.4, create-hmac@npm:^1.1.7": +"create-hash@npm:~1.1.3": + version: 1.1.3 + resolution: "create-hash@npm:1.1.3" + dependencies: + cipher-base: ^1.0.1 + inherits: ^2.0.1 + ripemd160: ^2.0.0 + sha.js: ^2.4.0 + checksum: 8d7d9bade6ab432f22737bf6f584155bab26d11b5abd98214034dda1e087bd2c395595f6729751b94d37f95f737dddffeb2db198bbbd5717a125906756ed3012 + languageName: node + linkType: hard + +"create-hmac@npm:^1.1.0, create-hmac@npm:^1.1.7": version: 1.1.7 resolution: "create-hmac@npm:1.1.7" dependencies: @@ -6890,6 +6969,17 @@ __metadata: languageName: node linkType: hard +"dunder-proto@npm:^1.0.1": + version: 1.0.1 + resolution: "dunder-proto@npm:1.0.1" + dependencies: + call-bind-apply-helpers: ^1.0.1 + es-errors: ^1.3.0 + gopd: ^1.2.0 + checksum: 149207e36f07bd4941921b0ca929e3a28f1da7bd6b6ff8ff7f4e2f2e460675af4576eeba359c635723dc189b64cdd4787e0255897d5b135ccc5d15cb8685fc90 + languageName: node + linkType: hard + "duplexer@npm:^0.1.2": version: 0.1.2 resolution: "duplexer@npm:0.1.2" @@ -7183,6 +7273,13 @@ __metadata: languageName: node linkType: hard +"es-define-property@npm:^1.0.1": + version: 1.0.1 + resolution: "es-define-property@npm:1.0.1" + checksum: 0512f4e5d564021c9e3a644437b0155af2679d10d80f21adaf868e64d30efdfbd321631956f20f42d655fedb2e3a027da479fad3fa6048f768eb453a80a5f80a + languageName: node + linkType: hard + "es-errors@npm:^1.2.1, es-errors@npm:^1.3.0": version: 1.3.0 resolution: "es-errors@npm:1.3.0" @@ -7199,6 +7296,15 @@ __metadata: languageName: node linkType: hard +"es-object-atoms@npm:^1.1.1": + version: 1.1.1 + resolution: "es-object-atoms@npm:1.1.1" + dependencies: + es-errors: ^1.3.0 + checksum: 214d3767287b12f36d3d7267ef342bbbe1e89f899cfd67040309fc65032372a8e60201410a99a1645f2f90c1912c8c49c8668066f6bdd954bcd614dda2e3da97 + languageName: node + linkType: hard + "es-set-tostringtag@npm:^2.0.3": version: 2.0.3 resolution: "es-set-tostringtag@npm:2.0.3" @@ -8249,6 +8355,15 @@ __metadata: languageName: node linkType: hard +"for-each@npm:^0.3.5": + version: 0.3.5 + resolution: "for-each@npm:0.3.5" + dependencies: + is-callable: ^1.2.7 + checksum: 3c986d7e11f4381237cc98baa0a2f87eabe74719eee65ed7bed275163082b940ede19268c61d04c6260e0215983b12f8d885e3c8f9aa8c2113bf07c37051745c + languageName: node + linkType: hard + "for-in@npm:^1.0.2": version: 1.0.2 resolution: "for-in@npm:1.0.2" @@ -8530,6 +8645,24 @@ __metadata: languageName: node linkType: hard +"get-intrinsic@npm:^1.3.0": + version: 1.3.0 + resolution: "get-intrinsic@npm:1.3.0" + dependencies: + call-bind-apply-helpers: ^1.0.2 + es-define-property: ^1.0.1 + es-errors: ^1.3.0 + es-object-atoms: ^1.1.1 + function-bind: ^1.1.2 + get-proto: ^1.0.1 + gopd: ^1.2.0 + has-symbols: ^1.1.0 + hasown: ^2.0.2 + math-intrinsics: ^1.1.0 + checksum: 301008e4482bb9a9cb49e132b88fee093bff373b4e6def8ba219b1e96b60158a6084f273ef5cafe832e42cd93462f4accb46a618d35fe59a2b507f2388c5b79d + languageName: node + linkType: hard + "get-port-please@npm:^2.2.0": version: 2.2.0 resolution: "get-port-please@npm:2.2.0" @@ -8539,6 +8672,16 @@ __metadata: languageName: node linkType: hard +"get-proto@npm:^1.0.1": + version: 1.0.1 + resolution: "get-proto@npm:1.0.1" + dependencies: + dunder-proto: ^1.0.1 + es-object-atoms: ^1.0.0 + checksum: 4fc96afdb58ced9a67558698b91433e6b037aaa6f1493af77498d7c85b141382cf223c0e5946f334fb328ee85dfe6edd06d218eaf09556f4bc4ec6005d7f5f7b + languageName: node + linkType: hard + "get-stdin@npm:^8.0.0": version: 8.0.0 resolution: "get-stdin@npm:8.0.0" @@ -8820,6 +8963,13 @@ __metadata: languageName: node linkType: hard +"gopd@npm:^1.2.0": + version: 1.2.0 + resolution: "gopd@npm:1.2.0" + checksum: cc6d8e655e360955bdccaca51a12a474268f95bb793fc3e1f2bdadb075f28bfd1fd988dab872daf77a61d78cbaf13744bc8727a17cfb1d150d76047d805375f3 + languageName: node + linkType: hard + "graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.15, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.4": version: 4.2.8 resolution: "graceful-fs@npm:4.2.8" @@ -8961,6 +9111,13 @@ __metadata: languageName: node linkType: hard +"has-symbols@npm:^1.1.0": + version: 1.1.0 + resolution: "has-symbols@npm:1.1.0" + checksum: b2316c7302a0e8ba3aaba215f834e96c22c86f192e7310bdf689dd0e6999510c89b00fbc5742571507cebf25764d68c988b3a0da217369a73596191ac0ce694b + languageName: node + linkType: hard + "has-tostringtag@npm:^1.0.0": version: 1.0.0 resolution: "has-tostringtag@npm:1.0.0" @@ -9034,6 +9191,15 @@ __metadata: languageName: node linkType: hard +"hash-base@npm:^2.0.0": + version: 2.0.2 + resolution: "hash-base@npm:2.0.2" + dependencies: + inherits: ^2.0.1 + checksum: e39f3f2bb91679ed350bd2eb81035acb1e1e6e9bb86d9f1197fcfdc3cf39a2c56bf82a1870f000fae651477883b4c107fd6ac0c640a18ab06298b87c39939396 + languageName: node + linkType: hard + "hash-base@npm:^3.0.0": version: 3.1.0 resolution: "hash-base@npm:3.1.0" @@ -10196,6 +10362,15 @@ __metadata: languageName: node linkType: hard +"is-typed-array@npm:^1.1.14": + version: 1.1.15 + resolution: "is-typed-array@npm:1.1.15" + dependencies: + which-typed-array: ^1.1.16 + checksum: ea7cfc46c282f805d19a9ab2084fd4542fed99219ee9dbfbc26284728bd713a51eac66daa74eca00ae0a43b61322920ba334793607dc39907465913e921e0892 + languageName: node + linkType: hard + "is-typedarray@npm:^1.0.0": version: 1.0.0 resolution: "is-typedarray@npm:1.0.0" @@ -10641,14 +10816,14 @@ __metadata: linkType: hard "koa@npm:^2.12.0": - version: 2.13.4 - resolution: "koa@npm:2.13.4" + version: 2.16.2 + resolution: "koa@npm:2.16.2" dependencies: accepts: ^1.3.5 cache-content-type: ^1.0.0 content-disposition: ~0.5.2 content-type: ^1.0.4 - cookies: ~0.8.0 + cookies: ~0.9.0 debug: ^4.3.2 delegates: ^1.0.0 depd: ^2.0.0 @@ -10667,7 +10842,7 @@ __metadata: statuses: ^1.5.0 type-is: ^1.6.16 vary: ^1.1.2 - checksum: c9a6f9c803433b2d143a0788308048c1432a71c5febcfea2af7f2e8bd732b9bfd75c2c220d553752ee9ab9a3f52490f006cfd521db97cd01d8461d67cc1ccc1f + checksum: c4c193c69fef15c4a7ed8bc30408871271272b1cec32fefa6fd1d1e8740b1b9a6b3e4dd65ecefb6dcfec0c3c40254637a96ffde99f530f6b569f2a777907d109 languageName: node linkType: hard @@ -11055,6 +11230,13 @@ __metadata: languageName: node linkType: hard +"math-intrinsics@npm:^1.1.0": + version: 1.1.0 + resolution: "math-intrinsics@npm:1.1.0" + checksum: 0e513b29d120f478c85a70f49da0b8b19bc638975eca466f2eeae0071f3ad00454c621bf66e16dd435896c208e719fc91ad79bbfba4e400fe0b372e7c1c9c9a2 + languageName: node + linkType: hard + "mathml-tag-names@npm:^2.1.3": version: 2.1.3 resolution: "mathml-tag-names@npm:2.1.3" @@ -12681,15 +12863,16 @@ __metadata: linkType: hard "pbkdf2@npm:^3.0.3, pbkdf2@npm:^3.1.2": - version: 3.1.2 - resolution: "pbkdf2@npm:3.1.2" + version: 3.1.3 + resolution: "pbkdf2@npm:3.1.3" dependencies: - create-hash: ^1.1.2 - create-hmac: ^1.1.4 - ripemd160: ^2.0.1 - safe-buffer: ^5.0.1 - sha.js: ^2.4.8 - checksum: 2c950a100b1da72123449208e231afc188d980177d021d7121e96a2de7f2abbc96ead2b87d03d8fe5c318face097f203270d7e27908af9f471c165a4e8e69c92 + create-hash: ~1.1.3 + create-hmac: ^1.1.7 + ripemd160: =2.0.1 + safe-buffer: ^5.2.1 + sha.js: ^2.4.11 + to-buffer: ^1.2.0 + checksum: afd1ec13044343ad877065b806d5b4d7625806139d22bec46cb146d1d52bb8debf4200767e33672b681e024307048e558a16f5997d86838d95552b88fa546530 languageName: node linkType: hard @@ -14572,13 +14755,20 @@ __metadata: languageName: node linkType: hard -"regenerator-runtime@npm:^0.13.4, regenerator-runtime@npm:^0.13.7": +"regenerator-runtime@npm:^0.13.7": version: 0.13.9 resolution: "regenerator-runtime@npm:0.13.9" checksum: 65ed455fe5afd799e2897baf691ca21c2772e1a969d19bb0c4695757c2d96249eb74ee3553ea34a91062b2a676beedf630b4c1551cc6299afb937be1426ec55e languageName: node linkType: hard +"regenerator-runtime@npm:^0.14.0": + version: 0.14.1 + resolution: "regenerator-runtime@npm:0.14.1" + checksum: 9f57c93277b5585d3c83b0cf76be47b473ae8c6d9142a46ce8b0291a04bb2cf902059f0f8445dcabb3fb7378e5fe4bb4ea1e008876343d42e46d3b484534ce38 + languageName: node + linkType: hard + "regenerator-transform@npm:^0.14.2": version: 0.14.5 resolution: "regenerator-transform@npm:0.14.5" @@ -14938,6 +15128,16 @@ __metadata: languageName: node linkType: hard +"ripemd160@npm:=2.0.1": + version: 2.0.1 + resolution: "ripemd160@npm:2.0.1" + dependencies: + hash-base: ^2.0.0 + inherits: ^2.0.1 + checksum: 865bcb4be1f04762c4afc9375f9172c326bed7057f388913512850493c22af9092efe21d7a488ec25665530333a1900f2f81d39b3fdfcc37a39f97b8f4ce13d0 + languageName: node + linkType: hard + "ripemd160@npm:^2.0.0, ripemd160@npm:^2.0.1": version: 2.0.2 resolution: "ripemd160@npm:2.0.2" @@ -15343,7 +15543,7 @@ __metadata: languageName: node linkType: hard -"set-function-length@npm:^1.2.1": +"set-function-length@npm:^1.2.1, set-function-length@npm:^1.2.2": version: 1.2.2 resolution: "set-function-length@npm:1.2.2" dependencies: @@ -15402,15 +15602,16 @@ __metadata: languageName: node linkType: hard -"sha.js@npm:^2.4.0, sha.js@npm:^2.4.8": - version: 2.4.11 - resolution: "sha.js@npm:2.4.11" +"sha.js@npm:^2.4.0, sha.js@npm:^2.4.11, sha.js@npm:^2.4.8": + version: 2.4.12 + resolution: "sha.js@npm:2.4.12" dependencies: - inherits: ^2.0.1 - safe-buffer: ^5.0.1 + inherits: ^2.0.4 + safe-buffer: ^5.2.1 + to-buffer: ^1.2.0 bin: - sha.js: ./bin.js - checksum: ebd3f59d4b799000699097dadb831c8e3da3eb579144fd7eb7a19484cbcbb7aca3c68ba2bb362242eb09e33217de3b4ea56e4678184c334323eca24a58e3ad07 + sha.js: bin.js + checksum: 9ec0fe39cc402acb33ffb18d261b52013485a2a9569a1873ff1861510a67b9ea2b3ccc78ab8aa09c34e1e85a5f06e18ab83637715509c6153ba8d537bbd2c29d languageName: node linkType: hard @@ -16544,6 +16745,28 @@ __metadata: languageName: node linkType: hard +"to-buffer@npm:^1.2.0": + version: 1.2.1 + resolution: "to-buffer@npm:1.2.1" + dependencies: + isarray: ^2.0.5 + safe-buffer: ^5.2.1 + typed-array-buffer: ^1.0.3 + checksum: a683dcf19bea02ed6af477513248d514b7590641170c2d64dd2b235bd9896193b0aea5f46ab64f50b787562aafce421569db6e44230b95beb8fb675a9169464b + languageName: node + linkType: hard + +"to-buffer@npm:^1.2.2": + version: 1.2.2 + resolution: "to-buffer@npm:1.2.2" + dependencies: + isarray: ^2.0.5 + safe-buffer: ^5.2.1 + typed-array-buffer: ^1.0.3 + checksum: b0cd2417989a9f3d47273301e8cec2c9798b19a117822424686f385f3ec0239d2defd5fd9f8e76cda0b21e2a2f5de65a58e806506bf4c296c31750c5efd3ae4b + languageName: node + linkType: hard + "to-fast-properties@npm:^2.0.0": version: 2.0.0 resolution: "to-fast-properties@npm:2.0.0" @@ -16780,6 +17003,17 @@ __metadata: languageName: node linkType: hard +"typed-array-buffer@npm:^1.0.3": + version: 1.0.3 + resolution: "typed-array-buffer@npm:1.0.3" + dependencies: + call-bound: ^1.0.3 + es-errors: ^1.3.0 + is-typed-array: ^1.1.14 + checksum: 3fb91f0735fb413b2bbaaca9fabe7b8fc14a3fa5a5a7546bab8a57e755be0e3788d893195ad9c2b842620592de0e68d4c077d4c2c41f04ec25b8b5bb82fa9a80 + languageName: node + linkType: hard + "typed-array-byte-length@npm:^1.0.1": version: 1.0.1 resolution: "typed-array-byte-length@npm:1.0.1" @@ -17822,6 +18056,21 @@ __metadata: languageName: node linkType: hard +"which-typed-array@npm:^1.1.16": + version: 1.1.19 + resolution: "which-typed-array@npm:1.1.19" + dependencies: + available-typed-arrays: ^1.0.7 + call-bind: ^1.0.8 + call-bound: ^1.0.4 + for-each: ^0.3.5 + get-proto: ^1.0.1 + gopd: ^1.2.0 + has-tostringtag: ^1.0.2 + checksum: 162d2a07f68ea323f88ed9419861487ce5d02cb876f2cf9dd1e428d04a63133f93a54f89308f337b27cabd312ee3d027cae4a79002b2f0a85b79b9ef4c190670 + languageName: node + linkType: hard + "which@npm:^1.3.1": version: 1.3.1 resolution: "which@npm:1.3.1"