diff --git a/README.md b/README.md index e81ec5a0a..82c9c8d4d 100644 --- a/README.md +++ b/README.md @@ -180,11 +180,11 @@ psql -U your_username -d worklenz_db -f database/sql/5_database_user.sql 5. Start the development servers: ```bash -# Terminal 1: Start the backend +# Backend (single command for build, watch, and auto-restart) cd worklenz-backend -npm run dev +npm run dev:all -# Terminal 2: Start the frontend +# Frontend (in another terminal) cd worklenz-frontend npm run dev ``` diff --git a/SETUP_THE_PROJECT.md b/SETUP_THE_PROJECT.md index 9a3568cd8..7cded4933 100644 --- a/SETUP_THE_PROJECT.md +++ b/SETUP_THE_PROJECT.md @@ -91,28 +91,26 @@ Getting started with development is a breeze! Follow these steps and you'll be c 6. **Run the Development Server:** + **Option 1: Combined development mode (Recommended)** + ```bash - npm run dev - ``` - - This starts the development server allowing you to work on the project. - -7. **Run the Production Server:** - - **a. Build the project:** - - ```bash - npm run build + npm run dev:all ``` + + This single command runs both the build watch process and the server with auto-restart. No need to run `npm run dev` and `npm start` separately. - This will compile the TypeScript code into JavaScript for production use. - - **b. Start the production server:** - + **Option 2: Separate commands** + ```bash + # Terminal 1: Build and watch for changes + npm run dev + + # Terminal 2: Start the server npm start ``` + The first option (`npm run dev:all`) is recommended as it simplifies the development workflow. + ## Docker Setup (Alternative) For an easier setup, you can use Docker and Docker Compose: diff --git a/worklenz-backend/README.md b/worklenz-backend/README.md index 96c6c5d51..0a972c83e 100644 --- a/worklenz-backend/README.md +++ b/worklenz-backend/README.md @@ -1,77 +1,117 @@ # Worklenz Backend -This is the Express.js backend for the Worklenz project management application. +This is the Express.js/TypeScript backend for the Worklenz project management application. + +## Prerequisites + +- Node.js >= 20.0.0 +- npm >= 8.11.0 +- PostgreSQL >= 12 ## Getting Started -Follow these steps to set up the backend for development: +### 1. Environment Configuration + +Create a `.env` file from the template: + +```bash +cp .env.template .env +``` + +Update the `.env` file with your specific configuration. Key variables include: + +- **Database**: `DB_USER`, `DB_PASSWORD`, `DB_NAME`, `DB_HOST`, `DB_PORT` +- **Server**: `PORT`, `NODE_ENV`, `SESSION_SECRET`, `COOKIE_SECRET` +- **Frontend**: `FRONTEND_URL`, `SERVER_CORS` +- **Storage**: Configure either S3 or Azure Blob Storage +- **Authentication**: Google OAuth credentials if needed + +### 2. Database Setup + +Create and initialize the database: + +```bash +# Create database +createdb worklenz_db + +# Run SQL setup files in order +psql -U postgres -d worklenz_db -f database/sql/0_extensions.sql +psql -U postgres -d worklenz_db -f database/sql/1_tables.sql +psql -U postgres -d worklenz_db -f database/sql/indexes.sql +psql -U postgres -d worklenz_db -f database/sql/4_functions.sql +psql -U postgres -d worklenz_db -f database/sql/triggers.sql +psql -U postgres -d worklenz_db -f database/sql/3_views.sql +psql -U postgres -d worklenz_db -f database/sql/2_dml.sql +psql -U postgres -d worklenz_db -f database/sql/5_database_user.sql +``` -1. **Configure Environment Variables:** +Or use the provided script: - - Create a copy of the `.env.example` file and name it `.env`. - - Update the required fields in `.env` with your specific configuration. +```bash +chmod +x database/00-init-db.sh +./database/00-init-db.sh +``` -2. **Set up Database:** - - Create a new database named `worklenz_db` on your local PostgreSQL server. - - Update the database connection details in your `.env` file. - - Execute the SQL setup files in the correct order: - - ```bash - # From your PostgreSQL client or command line - psql -U your_username -d worklenz_db -f database/sql/0_extensions.sql - psql -U your_username -d worklenz_db -f database/sql/1_tables.sql - psql -U your_username -d worklenz_db -f database/sql/indexes.sql - psql -U your_username -d worklenz_db -f database/sql/4_functions.sql - psql -U your_username -d worklenz_db -f database/sql/triggers.sql - psql -U your_username -d worklenz_db -f database/sql/3_views.sql - psql -U your_username -d worklenz_db -f database/sql/2_dml.sql - psql -U your_username -d worklenz_db -f database/sql/5_database_user.sql - ``` - - Alternatively, you can use the provided shell script: - - ```bash - # Make sure the script is executable - chmod +x database/00-init-db.sh - # Run the script (may need modifications for local execution) - ./database/00-init-db.sh - ``` +### 3. Install Dependencies -3. **Install Dependencies:** +```bash +npm install +``` - ```bash - npm install - ``` +## Development -4. **Run the Development Server:** +### Quick Start - ```bash - npm run dev - ``` +Run both build watch and server with auto-restart: - This starts the development server with hot reloading enabled. +```bash +npm run dev:all +``` -5. **Build for Production:** +This single command replaces the need to run `npm run dev` and `npm start` separately. It: +- Builds the TypeScript code in development mode +- Watches for file changes and rebuilds automatically +- Runs the server with nodemon for auto-restart on changes - ```bash - npm run build - ``` +### Alternative Development Commands - This will compile the TypeScript code into JavaScript for production use. +```bash +# Build and watch files only (no server) +npm run dev -6. **Start Production Server:** +# Build once for development +npm run build:dev + +# Start server only (after building) +npm start +``` - ```bash - npm start - ``` +## NPM Scripts + +| Script | Description | +|--------|-------------| +| `npm start` | Start the server | +| `npm run dev` | Build and watch files for development | +| `npm run dev:all` | Build, watch, and auto-restart server for development (recommended) | +| `npm run build` | Standard build | +| `npm run build:dev` | Development build | +| `npm run build:prod` | Production build with minification and compression | +| `npm test` | Run Jest tests | +| `npm run test:watch` | Run tests in watch mode | +| `npm run clean` | Clean build directory | +| `npm run compile` | Compile TypeScript | +| `npm run compile:dev` | Compile TypeScript for development | +| `npm run watch` | Watch TypeScript and asset files | +| `npm run watch:ts` | Watch TypeScript files only | +| `npm run watch:assets` | Watch asset files only | ## API Documentation -The API endpoints are organized into logical controllers and follow RESTful design principles. The main API routes are prefixed with `/api/v1`. +The API follows RESTful design principles with endpoints prefixed with `/api/`. ### Authentication -Authentication is handled via JWT tokens. Protected routes require a valid token in the Authorization header. +The API uses JWT tokens for authentication. Protected routes require a valid token in the Authorization header. ### File Storage @@ -93,4 +133,4 @@ npm test ## Docker Support -The backend can be run in a Docker container. See the main project README for Docker setup instructions. +The backend can be run in a Docker container. See the main project README for Docker setup instructions. \ No newline at end of file diff --git a/worklenz-backend/database/migrations/20250422132400-manual-task-progress.sql b/worklenz-backend/database/migrations/20250422132400-manual-task-progress.sql index c45d34af4..e915cac02 100644 --- a/worklenz-backend/database/migrations/20250422132400-manual-task-progress.sql +++ b/worklenz-backend/database/migrations/20250422132400-manual-task-progress.sql @@ -4,11 +4,20 @@ BEGIN; --- Add manual progress fields to tasks table -ALTER TABLE tasks -ADD COLUMN IF NOT EXISTS manual_progress BOOLEAN DEFAULT FALSE, -ADD COLUMN IF NOT EXISTS progress_value INTEGER DEFAULT NULL, -ADD COLUMN IF NOT EXISTS weight INTEGER DEFAULT NULL; +-- Create ENUM type for progress modes +CREATE TYPE PROGRESS_MODE_TYPE AS ENUM ('manual', 'weighted', 'time', 'default'); + +-- Alter tasks table to use ENUM type +ALTER TABLE tasks + ADD COLUMN IF NOT EXISTS manual_progress BOOLEAN DEFAULT FALSE, + ADD COLUMN IF NOT EXISTS progress_value INTEGER DEFAULT NULL, + ADD COLUMN IF NOT EXISTS progress_mode PROGRESS_MODE_TYPE DEFAULT 'default', + ADD COLUMN IF NOT EXISTS weight INTEGER DEFAULT NULL; + +ALTER TABLE projects + ADD COLUMN IF NOT EXISTS use_manual_progress BOOLEAN DEFAULT FALSE, + ADD COLUMN IF NOT EXISTS use_weighted_progress BOOLEAN DEFAULT FALSE, + ADD COLUMN IF NOT EXISTS use_time_progress BOOLEAN DEFAULT FALSE; -- Update function to consider manual progress CREATE OR REPLACE FUNCTION get_task_complete_ratio(_task_id uuid) RETURNS json diff --git a/worklenz-backend/database/sql/1_tables.sql b/worklenz-backend/database/sql/1_tables.sql index 937dacc1a..36ccca006 100644 --- a/worklenz-backend/database/sql/1_tables.sql +++ b/worklenz-backend/database/sql/1_tables.sql @@ -14,6 +14,8 @@ CREATE TYPE SCHEDULE_TYPE AS ENUM ('daily', 'weekly', 'yearly', 'monthly', 'ever CREATE TYPE LANGUAGE_TYPE AS ENUM ('en', 'es', 'pt', 'alb', 'de', 'zh_cn', 'ko'); +CREATE TYPE PROGRESS_MODE_TYPE AS ENUM ('manual', 'weighted', 'time', 'default'); + -- START: Users CREATE SEQUENCE IF NOT EXISTS users_user_no_seq START 1; @@ -777,7 +779,10 @@ CREATE TABLE IF NOT EXISTS projects ( estimated_man_days INTEGER DEFAULT 0, hours_per_day INTEGER DEFAULT 8, health_id UUID, - estimated_working_days INTEGER DEFAULT 0 + estimated_working_days INTEGER DEFAULT 0, + use_manual_progress BOOLEAN DEFAULT FALSE NOT NULL, + use_weighted_progress BOOLEAN DEFAULT FALSE NOT NULL, + use_time_progress BOOLEAN DEFAULT FALSE NOT NULL ); ALTER TABLE projects @@ -1414,7 +1419,11 @@ CREATE TABLE IF NOT EXISTS tasks ( priority_sort_order INTEGER DEFAULT 0 NOT NULL, phase_sort_order INTEGER DEFAULT 0 NOT NULL, billable BOOLEAN DEFAULT TRUE, - schedule_id UUID + schedule_id UUID, + manual_progress BOOLEAN DEFAULT FALSE NOT NULL, + progress_value INTEGER DEFAULT NULL, + progress_mode PROGRESS_MODE_TYPE DEFAULT 'default' NOT NULL, + weight INTEGER DEFAULT NULL ); ALTER TABLE tasks diff --git a/worklenz-backend/migrations-setup.md b/worklenz-backend/migrations-setup.md new file mode 100644 index 000000000..b6f7bd1ec --- /dev/null +++ b/worklenz-backend/migrations-setup.md @@ -0,0 +1,252 @@ +# Node-pg-migrate Setup for Worklenz + +## Installation + +```bash +npm install --save node-pg-migrate +npm install --save-dev @types/node-pg-migrate +``` + +## Configuration + +### 1. Add to package.json scripts: + +```json +{ + "scripts": { + "migrate": "node-pg-migrate", + "migrate:up": "node-pg-migrate up", + "migrate:down": "node-pg-migrate down", + "migrate:create": "node-pg-migrate create", + "migrate:redo": "node-pg-migrate redo" + } +} +``` + +### 2. Create migration config (.pgmrc or migrations/config.js): + +```javascript +// migrations/config.js +module.exports = { + databaseUrl: process.env.DATABASE_URL || { + host: process.env.DB_HOST, + port: process.env.DB_PORT, + database: process.env.DB_NAME, + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + }, + migrationsTable: 'pgmigrations', + dir: 'migrations', + direction: 'up', + count: undefined, + schema: 'public', + createSchema: false, + checkOrder: true, + migrationFilenameFormat: 'utc', + templateFileName: 'migration-template.ts' +}; +``` + +## Migration Structure + +### Initial Migration Plan (Convert existing SQL files): + +1. **001_extensions.ts** - Enable required extensions +2. **002_domains_and_types.ts** - Create custom domains and enum types +3. **003_core_tables.ts** - User, organization, and authentication tables +4. **004_project_tables.ts** - Project management tables +5. **005_task_tables.ts** - Task management tables +6. **006_indexes.ts** - Create all indexes +7. **007_functions.ts** - Stored procedures and functions +8. **008_triggers.ts** - Database triggers +9. **009_views.ts** - Database views +10. **010_initial_data.ts** - Seed data + +### Example Migration File: + +```typescript +// migrations/001_extensions.ts +import { MigrationBuilder } from 'node-pg-migrate'; + +export async function up(pgm: MigrationBuilder): Promise { + pgm.createExtension('uuid-ossp', { ifNotExists: true }); + pgm.createExtension('pg_trgm', { ifNotExists: true }); +} + +export async function down(pgm: MigrationBuilder): Promise { + pgm.dropExtension('pg_trgm', { ifExists: true }); + pgm.dropExtension('uuid-ossp', { ifExists: true }); +} +``` + +### Complex Migration Example (Tables with relations): + +```typescript +// migrations/003_core_tables.ts +import { MigrationBuilder } from 'node-pg-migrate'; + +export async function up(pgm: MigrationBuilder): Promise { + // Create custom domain + pgm.createDomain('wl_email', 'text', { + check: "value ~* '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$'" + }); + + // Create enum type + pgm.createType('language_type', ['en', 'es', 'pt', 'alb', 'de', 'zh_cn', 'ko']); + + // Create users table + pgm.createTable('users', { + id: { + type: 'uuid', + default: pgm.func('uuid_generate_v4()'), + primaryKey: true, + notNull: true + }, + email: { + type: 'wl_email', + notNull: true, + unique: true + }, + name: { + type: 'varchar(255)', + notNull: true + }, + password: { + type: 'text' + }, + language: { + type: 'language_type', + default: 'en' + }, + created_at: { + type: 'timestamp', + notNull: true, + default: pgm.func('current_timestamp') + } + }); + + // Create index + pgm.createIndex('users', 'email'); + pgm.createIndex('users', 'created_at'); +} + +export async function down(pgm: MigrationBuilder): Promise { + pgm.dropTable('users'); + pgm.dropType('language_type'); + pgm.dropDomain('wl_email'); +} +``` + +## Benefits for Worklenz + +1. **Incremental Updates**: New features can be added as new migrations +2. **Team Collaboration**: Developers can see exactly what DB changes were made +3. **CI/CD Integration**: Migrations can run automatically in deployment pipelines +4. **Development Safety**: Rollback capabilities for development environments +5. **Migration History**: Clear audit trail of all database changes + +## Migration Commands + +```bash +# Create a new migration +npm run migrate:create my_new_feature + +# Run all pending migrations +npm run migrate:up + +# Rollback last migration +npm run migrate:down + +# Rollback and re-run last migration +npm run migrate:redo + +# Run migrations up to specific version +npm run migrate:up 3 + +# Check migration status +npm run migrate -- status +``` + +## Transition Strategy + +### Phase 1: Setup (Week 1) +1. Install node-pg-migrate +2. Create migration config +3. Test connection and setup + +### Phase 2: Convert Existing Schema (Week 2-3) +1. Create baseline migration from current schema +2. Split large SQL files into logical migrations +3. Test migrations on fresh database + +### Phase 3: Validation (Week 4) +1. Compare migrated schema with original +2. Run application tests +3. Document any differences + +### Phase 4: Team Training & Rollout +1. Update documentation +2. Train team on migration workflow +3. Update CI/CD pipelines + +## Best Practices + +1. **Small, Focused Migrations**: Each migration should do one thing +2. **Always Include Down**: Make migrations reversible +3. **Test Migrations**: Run up and down in development before committing +4. **No Data Modifications in Schema Migrations**: Separate schema and data migrations +5. **Use Transactions**: Wrap migrations in transactions when possible +6. **Version Control**: Commit migrations with related code changes + +## Handling Large Functions/Procedures + +For the 269KB functions file, consider: + +```typescript +// migrations/007_functions.ts +import { MigrationBuilder } from 'node-pg-migrate'; +import * as fs from 'fs'; +import * as path from 'path'; + +export async function up(pgm: MigrationBuilder): Promise { + // Read function definitions from separate SQL files + const functionsDir = path.join(__dirname, 'sql', 'functions'); + const files = fs.readdirSync(functionsDir).sort(); + + for (const file of files) { + const sql = fs.readFileSync(path.join(functionsDir, file), 'utf8'); + pgm.sql(sql); + } +} + +export async function down(pgm: MigrationBuilder): Promise { + // Drop functions in reverse order + // Or maintain a list of function names to drop +} +``` + +## Considerations + +### Pros: +- Professional migration management +- Better for teams and production +- Supports complex deployment scenarios +- Industry standard approach + +### Cons: +- Initial setup effort required +- Team learning curve +- Need to convert existing SQL files +- More complex than raw SQL for simple schemas + +## Recommendation + +Given Worklenz's complexity (100+ tables, 269KB of functions, multiple developers), implementing node-pg-migrate would provide: + +1. **Better maintainability** for the growing schema +2. **Safer deployments** with rollback capabilities +3. **Clear change history** for debugging +4. **Easier onboarding** for new developers +5. **Professional-grade** database management + +The initial investment in setup will pay dividends as the application grows and the team expands. \ No newline at end of file diff --git a/worklenz-backend/nodemon.json b/worklenz-backend/nodemon.json new file mode 100644 index 000000000..337d848c2 --- /dev/null +++ b/worklenz-backend/nodemon.json @@ -0,0 +1,14 @@ +{ + "watch": ["build"], + "ext": "js", + "ignore": [ + "build/**/*.map", + "build/**/*.tmp", + "build/public/**", + "build/views/**" + ], + "delay": "1000", + "env": { + "NODE_ENV": "development" + } +} \ No newline at end of file diff --git a/worklenz-backend/package-lock.json b/worklenz-backend/package-lock.json index 4fffff201..fb3903c6d 100644 --- a/worklenz-backend/package-lock.json +++ b/worklenz-backend/package-lock.json @@ -25,7 +25,6 @@ "cron": "^2.4.0", "crypto-js": "^4.1.1", "csrf-sync": "^4.2.1", - "csurf": "^1.11.0", "debug": "^4.3.4", "dotenv": "^16.3.1", "exceljs": "^4.3.0", @@ -76,7 +75,6 @@ "@types/cookie-signature": "^1.1.2", "@types/cron": "^2.0.1", "@types/crypto-js": "^4.2.2", - "@types/csurf": "^1.11.2", "@types/express": "^4.17.21", "@types/express-brute": "^1.0.2", "@types/express-brute-redis": "^0.0.4", @@ -118,6 +116,7 @@ "jest-sonar-reporter": "^2.0.0", "ncp": "^2.0.0", "nodeman": "^1.1.2", + "nodemon": "^3.1.10", "rimraf": "^6.0.1", "swagger-jsdoc": "^6.2.8", "terser": "^5.40.0", @@ -5483,16 +5482,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/csurf": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/@types/csurf/-/csurf-1.11.5.tgz", - "integrity": "sha512-5rw87+5YGixyL2W8wblSUl5DSZi5YOlXE6Awwn2ofLvqKr/1LruKffrQipeJKUX44VaxKj8m5es3vfhltJTOoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/express-serve-static-core": "*" - } - }, "node_modules/@types/express": { "version": "4.17.23", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.23.tgz", @@ -6507,13 +6496,13 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.10.0.tgz", - "integrity": "sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.1.tgz", + "integrity": "sha512-Kn4kbSXpkFHCGE6rBFNwIv0GQs4AvDT80jlveJDKFxjbTYMUeB4QtsdPCv6H8Cm19Je7IU6VFtRl2zWZI0rudQ==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", + "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, @@ -7523,16 +7512,16 @@ } }, "node_modules/compression": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.0.tgz", - "integrity": "sha512-k6WLKfunuqCYD3t6AsuPGvQWaKwuLLh2/xHNcX4qE+vIfDNXpSqnrhwA7O53R7WVQUnt8dVAIW+YHr7xTgOgGA==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", "license": "MIT", "dependencies": { "bytes": "3.1.2", "compressible": "~2.0.18", "debug": "2.6.9", "negotiator": "~0.6.4", - "on-headers": "~1.0.2", + "on-headers": "~1.1.0", "safe-buffer": "5.2.1", "vary": "~1.1.2" }, @@ -7836,20 +7825,6 @@ "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==", "license": "MIT" }, - "node_modules/csrf": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/csrf/-/csrf-3.1.0.tgz", - "integrity": "sha512-uTqEnCvWRk042asU6JtapDTcJeeailFy4ydOQS28bj1hcLnYRiqi8SsD2jS412AY1I/4qdOwWZun774iqywf9w==", - "license": "MIT", - "dependencies": { - "rndm": "1.2.0", - "tsscmp": "1.0.6", - "uid-safe": "2.1.5" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/csrf-sync": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/csrf-sync/-/csrf-sync-4.2.1.tgz", @@ -7859,80 +7834,6 @@ "http-errors": "^2.0.0" } }, - "node_modules/csurf": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/csurf/-/csurf-1.11.0.tgz", - "integrity": "sha512-UCtehyEExKTxgiu8UHdGvHj4tnpE/Qctue03Giq5gPgMQ9cg/ciod5blZQ5a4uCEenNQjxyGuzygLdKUmee/bQ==", - "deprecated": "This package is archived and no longer maintained. For support, visit https://github.com/expressjs/express/discussions", - "license": "MIT", - "dependencies": { - "cookie": "0.4.0", - "cookie-signature": "1.0.6", - "csrf": "3.1.0", - "http-errors": "~1.7.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/csurf/node_modules/cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/csurf/node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/csurf/node_modules/http-errors": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", - "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", - "license": "MIT", - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/csurf/node_modules/setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", - "license": "ISC" - }, - "node_modules/csurf/node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/csurf/node_modules/toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, "node_modules/dayjs": { "version": "1.11.13", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", @@ -8985,16 +8886,16 @@ } }, "node_modules/express-session": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.1.tgz", - "integrity": "sha512-a5mtTqEaZvBCL9A9aqkrtfz+3SMDhOVUnjafjo+s7A9Txkq+SVX2DLvSp1Zrv4uCXa3lMSK3viWnh9Gg07PBUA==", + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.2.tgz", + "integrity": "sha512-SZjssGQC7TzTs9rpPDuUrR23GNZ9+2+IkA/+IJWmvQilTr5OSliEHGF+D9scbIpdC6yGtTI0/VhaHoVes2AN/A==", "license": "MIT", "dependencies": { "cookie": "0.7.2", "cookie-signature": "1.0.7", "debug": "2.6.9", "depd": "~2.0.0", - "on-headers": "~1.0.2", + "on-headers": "~1.1.0", "parseurl": "~1.3.3", "safe-buffer": "5.2.1", "uid-safe": "~2.1.5" @@ -9373,9 +9274,9 @@ } }, "node_modules/form-data": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.3.tgz", - "integrity": "sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", "license": "MIT", "dependencies": { "asynckit": "^0.4.0", @@ -10012,6 +9913,13 @@ "node": ">= 4" } }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, "node_modules/immediate": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", @@ -11858,16 +11766,16 @@ } }, "node_modules/morgan": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", - "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.1.tgz", + "integrity": "sha512-223dMRJtI/l25dJKWpgij2cMtywuG/WiUKXdvwfbhGKBhy1puASqXwFzmWZ7+K73vUPoR7SS2Qz2cI/g9MKw0A==", "license": "MIT", "dependencies": { "basic-auth": "~2.0.1", "debug": "2.6.9", "depd": "~2.0.0", "on-finished": "~2.3.0", - "on-headers": "~1.0.2" + "on-headers": "~1.1.0" }, "engines": { "node": ">= 0.8.0" @@ -12049,6 +11957,84 @@ "node": "*" } }, + "node_modules/nodemon": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.10.tgz", + "integrity": "sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/nodemon/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/nodemon/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/nodemon/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/nopt": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", @@ -12139,9 +12125,9 @@ } }, "node_modules/on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", "license": "MIT", "engines": { "node": ">= 0.8" @@ -12899,6 +12885,13 @@ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", "license": "MIT" }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, "node_modules/pug": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/pug/-/pug-3.0.3.tgz", @@ -13402,12 +13395,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/rndm": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/rndm/-/rndm-1.2.0.tgz", - "integrity": "sha512-fJhQQI5tLrQvYIYFpOnFinzv9dwmR7hRnUz1XqP3OJ1jIweTNOd6aTO4jwQSgcBSFUB+/KHJxuGneime+FdzOw==", - "license": "MIT" - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -13845,6 +13832,32 @@ "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", "license": "MIT" }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -14567,9 +14580,9 @@ "license": "GPL-2.0-or-later" }, "node_modules/tmp": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", - "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", + "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", "license": "MIT", "engines": { "node": ">=14.14" @@ -14610,6 +14623,16 @@ "integrity": "sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg==", "license": "MIT" }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -14970,15 +14993,6 @@ "typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev" } }, - "node_modules/tsscmp": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", - "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==", - "license": "MIT", - "engines": { - "node": ">=0.6.x" - } - }, "node_modules/tsutils": { "version": "3.21.0", "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", @@ -15107,6 +15121,13 @@ "integrity": "sha512-IevTus0SbGwQzYh3+fRsAMTVVPOoIVufzacXcHPmdlle1jUpq7BRL+mw3dgeLanvGZdwwbWhRV6XrcFNdBmjWA==", "license": "MIT" }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", diff --git a/worklenz-backend/package.json b/worklenz-backend/package.json index 1b8d140ff..810666e63 100644 --- a/worklenz-backend/package.json +++ b/worklenz-backend/package.json @@ -14,6 +14,7 @@ "test": "jest", "start": "node build/bin/www.js", "dev": "npm run build:dev && npm run watch", + "dev:all": "npm run build:dev && concurrently \"npm run watch\" \"nodemon build/bin/www.js\"", "build": "npm run clean && npm run compile && npm run copy && npm run compress", "build:dev": "npm run clean && npm run compile:dev && npm run copy", "build:prod": "npm run clean && npm run compile:prod && npm run copy && npm run minify && npm run compress", @@ -60,7 +61,6 @@ "cron": "^2.4.0", "crypto-js": "^4.1.1", "csrf-sync": "^4.2.1", - "csurf": "^1.11.0", "debug": "^4.3.4", "dotenv": "^16.3.1", "exceljs": "^4.3.0", @@ -111,7 +111,6 @@ "@types/cookie-signature": "^1.1.2", "@types/cron": "^2.0.1", "@types/crypto-js": "^4.2.2", - "@types/csurf": "^1.11.2", "@types/express": "^4.17.21", "@types/express-brute": "^1.0.2", "@types/express-brute-redis": "^0.0.4", @@ -153,6 +152,7 @@ "jest-sonar-reporter": "^2.0.0", "ncp": "^2.0.0", "nodeman": "^1.1.2", + "nodemon": "^3.1.10", "rimraf": "^6.0.1", "swagger-jsdoc": "^6.2.8", "terser": "^5.40.0", diff --git a/worklenz-frontend/package-lock.json b/worklenz-frontend/package-lock.json index bf437005e..aaac4cd9c 100644 --- a/worklenz-frontend/package-lock.json +++ b/worklenz-frontend/package-lock.json @@ -3996,18 +3996,6 @@ "node": ">=6" } }, - "node_modules/detect-libc": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", - "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", - "dev": true, - "license": "Apache-2.0", - "optional": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -4996,18 +4984,6 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jiti": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", - "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "bin": { - "jiti": "lib/jiti-cli.mjs" - } - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -5171,257 +5147,6 @@ "html2canvas": "^1.0.0-rc.5" } }, - "node_modules/lightningcss": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", - "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", - "dev": true, - "license": "MPL-2.0", - "optional": true, - "peer": true, - "dependencies": { - "detect-libc": "^2.0.3" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-darwin-arm64": "1.30.1", - "lightningcss-darwin-x64": "1.30.1", - "lightningcss-freebsd-x64": "1.30.1", - "lightningcss-linux-arm-gnueabihf": "1.30.1", - "lightningcss-linux-arm64-gnu": "1.30.1", - "lightningcss-linux-arm64-musl": "1.30.1", - "lightningcss-linux-x64-gnu": "1.30.1", - "lightningcss-linux-x64-musl": "1.30.1", - "lightningcss-win32-arm64-msvc": "1.30.1", - "lightningcss-win32-x64-msvc": "1.30.1" - } - }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz", - "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "peer": true, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz", - "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "peer": true, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz", - "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "peer": true, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz", - "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz", - "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz", - "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz", - "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz", - "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz", - "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "peer": true, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz", - "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "peer": true, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, "node_modules/lilconfig": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",