From 4fd4ef7d4738f1f26f81e2dd339b7284d3db07ab Mon Sep 17 00:00:00 2001 From: Raphael Bessin Date: Tue, 24 Feb 2026 18:07:04 -0500 Subject: [PATCH 1/3] setup docs site with docs as source of truth --- .gitignore | 3 + docs-site/.gitignore | 23 + docs-site/README.md | 283 + docs-site/babel.config.js | 3 + .../general-practices/backend-endpoints.md | 442 ++ .../docs/general-practices/frontend-forms.md | 621 ++ .../frontend-hooks-and-apis.md | 471 ++ .../general-practices/postman-api-testing.md | 321 + .../prisma-schema-shared-types.md | 622 ++ .../query-args-and-transformers.md | 516 ++ .../general-practices/react-components.md | 548 ++ .../general-practices/repository-overview.md | 343 + docs-site/docs/intro.md | 45 + docs-site/docusaurus.config.js | 97 + docs-site/package.json | 48 + docs-site/scripts/generate-sidebar.js | 104 + docs-site/scripts/sync-skills.js | 224 + docs-site/src/css/custom.css | 30 + docs-site/src/pages/index.js | 6 + docs-site/static/img/favicon.ico | Bin 0 -> 261950 bytes docs-site/static/img/logo.png | Bin 0 -> 487234 bytes package.json | 11 +- yarn.lock | 6501 ++++++++++++++++- 23 files changed, 11129 insertions(+), 133 deletions(-) create mode 100644 docs-site/.gitignore create mode 100644 docs-site/README.md create mode 100644 docs-site/babel.config.js create mode 100644 docs-site/docs/general-practices/backend-endpoints.md create mode 100644 docs-site/docs/general-practices/frontend-forms.md create mode 100644 docs-site/docs/general-practices/frontend-hooks-and-apis.md create mode 100644 docs-site/docs/general-practices/postman-api-testing.md create mode 100644 docs-site/docs/general-practices/prisma-schema-shared-types.md create mode 100644 docs-site/docs/general-practices/query-args-and-transformers.md create mode 100644 docs-site/docs/general-practices/react-components.md create mode 100644 docs-site/docs/general-practices/repository-overview.md create mode 100644 docs-site/docs/intro.md create mode 100644 docs-site/docusaurus.config.js create mode 100644 docs-site/package.json create mode 100644 docs-site/scripts/generate-sidebar.js create mode 100644 docs-site/scripts/sync-skills.js create mode 100644 docs-site/src/css/custom.css create mode 100644 docs-site/src/pages/index.js create mode 100644 docs-site/static/img/favicon.ico create mode 100644 docs-site/static/img/logo.png diff --git a/.gitignore b/.gitignore index f77840056a..31c6f7a945 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,9 @@ *.env .agent +# Generated Claude skills (source is docs-site/docs/) +.claude/skills/ + npm-debug.log* yarn-debug.log* yarn-error.log* diff --git a/docs-site/.gitignore b/docs-site/.gitignore new file mode 100644 index 0000000000..7dbe29a8f5 --- /dev/null +++ b/docs-site/.gitignore @@ -0,0 +1,23 @@ +# Dependencies +node_modules/ +/.pnp +.pnp.js + +# Production +/build + +# Generated files +.docusaurus +.cache-loader +sidebars.js + +# Misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/docs-site/README.md b/docs-site/README.md new file mode 100644 index 0000000000..1759795432 --- /dev/null +++ b/docs-site/README.md @@ -0,0 +1,283 @@ +# FinishLine Documentation Site + +This directory contains the Docusaurus-based documentation site for FinishLine developers. + +## Architecture + +**Source of Truth:** `docs-site/docs/` contains all developer documentation in standard Docusaurus markdown format. + +**Claude AI Integration:** Documentation files flagged with `skill: true` in their frontmatter are automatically synced to `.claude/skills/` for Claude AI to use as context when helping with development. + +### Workflow + +1. **Developers edit**: `docs-site/docs/` (tracked in Git) +2. **Run sync**: `yarn skills:sync` generates `.claude/skills/` (gitignored) +3. **Claude reads**: `.claude/skills/` to understand the codebase + +This approach allows us to: + +- Maintain comprehensive documentation for developers +- Selectively sync relevant docs to Claude's skills +- Have docs-only content (deployment, architecture) that Claude doesn't need + +## Prerequisites + +- Node.js 18 or higher +- Yarn package manager (this project uses Yarn workspaces) + +## Setup + +The docs-site is part of the FinishLine monorepo workspace. Dependencies are managed from the root: + +```bash +# From the FinishLine root directory +yarn install +``` + +This will install all dependencies for docs-site along with the rest of the project. + +## Development + +### Running the documentation site locally: + +**From the root directory:** + +```bash +yarn docs:dev +``` + +**Or from within docs-site:** + +```bash +cd docs-site +yarn start +``` + +The Docusaurus development server will start at `http://localhost:3002`. + +The site will automatically reload when you edit files in `docs/`. + +## Building for Production + +To create a production build: + +**From root:** + +```bash +yarn docs:build +``` + +**Or from docs-site:** + +```bash +cd docs-site +yarn build +``` + +The static site will be generated in the `build/` directory. + +To test the production build locally: + +```bash +yarn docs:serve +``` + +## Syncing Skills for Claude + +After editing documentation that should be available to Claude: + +```bash +yarn skills:sync +``` + +This command: + +1. Scans all files in `docs/` for `skill: true` in frontmatter +2. Transforms them to Claude's SKILL.md format +3. Writes them to `.claude/skills/` (gitignored) + +**When to sync:** + +- After adding or editing documentation flagged as a skill +- Before using Claude for development (to ensure it has latest context) +- Can be automated in a pre-commit hook if desired + +## Project Structure + +``` +docs-site/ +├── docs/ # Source of truth - developer documentation +│ ├── intro.md +│ └── general-practices/ +│ ├── backend-endpoints.md +│ └── ... +├── scripts/ +│ ├── sync-skills.js # Generate .claude/skills/ from docs/ +│ └── generate-sidebar.js # Auto-generate sidebars.js from docs/ structure +├── src/ +│ ├── css/ +│ │ └── custom.css # Custom styling +│ └── pages/ +│ └── index.js # Homepage redirect +├── static/ +│ └── img/ # Static assets (logos, favicon) +├── docusaurus.config.js # Docusaurus configuration +├── sidebars.js # Auto-generated sidebar (gitignored) +└── package.json # Dependencies and scripts +``` + +## Adding New Documentation + +### For All Documentation (Developers): + +1. **Create a new markdown file** in `docs/`: + + ```bash + docs/deployment/github-actions.md + ``` + +2. **Add frontmatter:** + + ```yaml + --- + title: GitHub Actions Deployment + description: Guide for deploying FinishLine using GitHub Actions + skill: false # This is docs-only, not a Claude skill + --- + ``` + +3. **Test it:** + ```bash + yarn docs:dev + ``` + +The sidebar will be automatically generated from the folder structure! + +### For Documentation That Should Be a Claude Skill: + +1. **Create the markdown file** as above + +2. **Use `skill: true` in frontmatter:** + + ```yaml + --- + title: Backend Endpoints + description: Guide for creating API endpoints + skill: true + skill_name: backend-endpoints # Maps to folder name in .claude/skills/ + --- + ``` + +3. **Sync to Claude:** + ```bash + yarn skills:sync + ``` + +The sidebar will be automatically generated! + +### Organizing Documentation + +The sidebar navigation is **automatically generated** from the `docs/` folder structure: + +- **Reorder pages**: Rename files (alphabetical order is used) +- **Create categories**: Create nested folders in `docs/` +- **Change labels**: Folder names become category labels (use hyphens: `my-category`) + +The sidebar regenerates automatically when you run `yarn docs:dev` or `yarn docs:build`. + +You can also manually regenerate it: +```bash +yarn generate-sidebar +``` + +## Frontmatter Fields + +All documentation files should have frontmatter: + +| Field | Required | Purpose | Example | +| ------------- | ------------- | ------------------------------ | ---------------------------------- | +| `title` | Yes | Page title | `Backend Endpoints` | +| `description` | Yes | Page description | `Guide for creating API endpoints` | +| `skill` | Yes | Should sync to Claude? | `true` or `false` | +| `skill_name` | If skill:true | Folder name in .claude/skills/ | `backend-endpoints` | + +## Customization + +### Navbar and Footer + +Edit `docusaurus.config.js` to customize: + +- Site title and tagline +- Navbar links +- GitHub repository links +- Production URL + +### Styling + +Edit `src/css/custom.css` to customize: + +- Primary colors (currently set to NER red: #ef4345) +- Dark mode colors +- Font sizes and spacing +- Custom component styles + +### Sidebar Navigation + +The sidebar is **automatically generated** from the `docs/` folder structure. To customize it: + +- **Reorder pages**: Rename files (alphabetical sorting) +- **Create categories**: Create nested folders in `docs/` +- **Change labels**: Folder names become category labels (use hyphens: `my-category`) + +The sidebar regenerates each time you run `yarn docs:dev` or `yarn docs:build`. + +## Troubleshooting + +### Documentation not updating + +If your changes aren't appearing: + +1. Stop the dev server (Ctrl+C) +2. Clear the cache: `yarn clear` +3. Run `yarn docs:dev` again + +### Build errors + +Common issues: + +- **Node version**: Ensure you're running Node.js 18 or higher +- **Dependencies**: From the root directory, try `rm -rf docs-site/node_modules && yarn install` +- **Port conflict**: Docs run on port 3002. If it's in use, Docusaurus will try another port or you can stop the conflicting process + +### Skills not syncing + +If `yarn skills:sync` doesn't generate expected skills: + +- Verify the doc has `skill: true` in frontmatter +- Verify `skill_name` is set for all docs with `skill: true` +- Check the console output for warnings +- Ensure `.claude/skills/` is gitignored (it will be regenerated) + +## Future Enhancements + +Potential improvements for future iterations: + +- **Public deployment**: Deploy to GitHub Pages or Vercel +- **Search functionality**: Add DocSearch or local search plugin +- **Versioning**: Support documentation for multiple FinishLine versions +- **Interactive components**: Add live code examples or API explorers +- **Automated sync**: Pre-commit hook to run skills:sync automatically + +## Contributing + +When contributing to the documentation: + +1. Edit markdown files in `docs-site/docs/` +2. Test your changes locally with `yarn docs:dev` (sidebar auto-generates) +3. If you edited a skill doc (`skill: true`), run `yarn skills:sync` +4. Ensure the site builds successfully with `yarn docs:build` +5. Submit a PR with your documentation changes + +## License + +This documentation is part of the FinishLine project, licensed under GNU AGPLv3. diff --git a/docs-site/babel.config.js b/docs-site/babel.config.js new file mode 100644 index 0000000000..e00595dae7 --- /dev/null +++ b/docs-site/babel.config.js @@ -0,0 +1,3 @@ +module.exports = { + presets: [require.resolve('@docusaurus/core/lib/babel/preset')], +}; diff --git a/docs-site/docs/general-practices/backend-endpoints.md b/docs-site/docs/general-practices/backend-endpoints.md new file mode 100644 index 0000000000..6cc6782f20 --- /dev/null +++ b/docs-site/docs/general-practices/backend-endpoints.md @@ -0,0 +1,442 @@ +--- +title: Backend Endpoints +description: Guide for creating backend API endpoints in FinishLine following the Route → Controller → Service pattern with multi-tenant security. Use when creating new endpoints, adding API routes, implementing controllers or services, building backend request handlers, or when asked how the backend works. +skill: true +skill_name: backend-endpoints +--- + +# Backend Endpoints + +> **Summary:** Every backend endpoint in FinishLine follows a three-layer pattern: Route (validation) → Controller (request extraction) → Service (business logic). This skill walks through the full pattern and how to add a new endpoint from scratch. + +## Overview + +FinishLine's backend is an Express.js application written in TypeScript. All request handling is split into three distinct layers with clear responsibilities: + +1. **Routes** define the HTTP method and path, declare validation rules using `express-validator`, and point to a controller method. They contain zero business logic. +2. **Controllers** are thin glue — they extract data from `req.params`, `req.body`, and `req.query`, call the appropriate service method, and return the result as JSON. They MUST delegate all errors to Express via `next(error)`. +3. **Services** contain all business logic: permission checks, database queries via Prisma, data transformation, and side effects (Slack notifications, Google integrations, etc.). Services throw custom exceptions when something goes wrong. + +Two key objects are available on every request thanks to global middleware: `req.currentUser` (the authenticated `User`) and `req.organization` (the Prisma `Organization` record). These are set by the `getUserAndOrganization` middleware in `src/backend/index.ts` and typed via `src/backend/custom.d.ts`. + +## Architecture + +``` + Client Request + │ + ▼ +┌──────────────┐ JWT validated, user +│ Middleware │ and organization +│ (global) │ attached to req +└──────┬───────┘ + │ + ▼ +┌──────────────┐ express-validator +│ Route │ rules, then +│ │ validateInputs +└──────┬───────┘ + │ + ▼ +┌──────────────┐ Extract params/body, +│ Controller │ call service, return +│ (thin) │ JSON, pass errors +│ │ to next() +└──────┬───────┘ + │ + ▼ +┌──────────────┐ Permission checks, +│ Service │ Prisma queries, +│ │ transformers, +│ │ side effects +└──────┬───────┘ + │ + ▼ +┌──────────────┐ +│ Prisma DB │ +└──────────────┘ +``` + +If a service throws an exception, it bubbles up through the controller's `next(error)` call and is caught by the global `errorHandler` middleware registered at the bottom of `src/backend/index.ts`. + +## File Locations + +| Layer | Path | Naming | +|-------|------|--------| +| Entry point | `src/backend/index.ts` | — | +| Routes | `src/backend/src/routes/{feature}.routes.ts` | `{feature}Router` | +| Controllers | `src/backend/src/controllers/{feature}.controllers.ts` | `{Feature}Controller` class | +| Services | `src/backend/src/services/{feature}.services.ts` | `{Feature}Service` class | +| Validation | `src/backend/src/utils/validation.utils.ts` | Shared validators | +| Errors | `src/backend/src/utils/errors.utils.ts` | `HttpException` subclasses | +| Express types | `src/backend/custom.d.ts` | `currentUser` and `organization` on `Request` | + +For query args and transformers, see the [query-args-and-transformers](./query-args-and-transformers) skill. + +## How Endpoint URLs Work + +The full URL path for any endpoint is the **combination** of the base path registered in `src/backend/index.ts` and the route path in the router file. This is a very common source of confusion. + +For example, if `index.ts` registers: +```typescript +app.use('/calendar', calendarRouter); +``` + +And the router defines: +```typescript +calendarRouter.post('/shop/create', ...); +``` + +Then the actual endpoint URL is `POST /calendar/shop/create`. The base path `/calendar` comes from `index.ts`, and `/shop/create` comes from the route file. Always mentally concatenate these two when figuring out or defining an endpoint's URL. + +## Step-by-Step: Adding a New Endpoint + +This walkthrough adds a hypothetical `POST /calendar/shop/create` endpoint. + +### Step 1: Define the Route + +Add validation rules using `express-validator` and the helpers from `validation.utils.ts`. Always end the chain with `validateInputs` before the controller method. + +```typescript +// src/backend/src/routes/calendar.routes.ts +import express from 'express'; +import { body } from 'express-validator'; +import { + nonEmptyString, + isDate, + validateInputs +} from '../utils/validation.utils.js'; +import CalendarController + from '../controllers/calendar.controllers.js'; + +const calendarRouter = express.Router(); + +calendarRouter.post( + '/shop/create', + nonEmptyString(body('name')), + nonEmptyString(body('description')), + isDate(body('dateEstablished')), + validateInputs, + CalendarController.createShop +); + +export default calendarRouter; +``` + +**Key rules for routes:** + +- Use `GET` for all read operations. Use `POST` for all mutations (create, edit, delete). NEVER use `PUT`, `PATCH`, or `DELETE` HTTP methods. +- Delete endpoints follow the pattern `POST '/{entity}/:id/delete'`. +- Always call `validateInputs` as the last middleware before the controller. +- Use the shared validation helpers (`nonEmptyString`, `intMinZero`, `isDate`, etc.) instead of writing raw `express-validator` chains. +- For array fields, validate both the array and its items: `body('ids').isArray()` then `body('ids.*').isString()`. +- URL params use `param()`, query strings use `query()`, body fields use `body()`. + +**When to abstract validators:** Keep validation inline in the route by default. Only extract validators into `validation.utils.ts` when: +- The request body contains a **nested object** that is itself a known entity (e.g., a work package embedded inside a project create payload). Create a named validator array like `workPackageProposedChangesValidators`. +- The **same set of validations** is repeated across multiple routes (e.g., `descriptionBulletsValidators` used in both work package and project routes). + +For a simple endpoint with a few string/number/date fields, just write the validators inline. + +### Step 2: Register the Router (if new feature) + +If creating a brand new feature router, register it in `src/backend/index.ts`: + +```typescript +// src/backend/index.ts +import calendarRouter + from './src/routes/calendar.routes.js'; + +// ... after getUserAndOrganization middleware ... +app.use('/calendar', calendarRouter); +``` + +Remember: the full endpoint URL is `index.ts` base path + route path = `POST /calendar/shop/create`. + +### Step 3: Write the Controller Method + +Controllers follow a rigid structure: try/catch, extract request data, call service, return JSON, pass errors to `next`. + +```typescript +// src/backend/src/controllers/calendar.controllers.ts +import { NextFunction, Request, Response } from 'express'; +import CalendarService + from '../services/calendar.services.js'; + +export default class CalendarController { + static async createShop( + req: Request, + res: Response, + next: NextFunction + ) { + try { + const { name, description, dateEstablished } + = req.body; + + // Parse date strings to Date objects + // before passing to the service + const parsedDate = new Date(dateEstablished); + + const shop = await CalendarService.createShop( + req.currentUser, + name, + description, + parsedDate, + req.organization + ); + + res.status(200).json(shop); + } catch (error: unknown) { + next(error); + } + } +} +``` + +**Key rules for controllers:** + +- Every method MUST be `static async` with signature `(req: Request, res: Response, next: NextFunction)`. +- Every method body MUST be wrapped in `try { ... } catch (error: unknown) { next(error); }`. +- NEVER handle errors directly in the controller. Always call `next(error)`. +- Extract URL params with: `const { id } = req.params as Record;` +- **Parse date strings to `Date` objects in the controller** before passing to the service: `new Date(startTime)`. +- Always pass `req.currentUser` and `req.organization` to service methods that need them. +- Return `res.status(200).json(result)` for all successful responses. +- Controllers contain ZERO business logic — no permission checks, no database queries. + +### Step 4: Write the Service Method + +Services contain all business logic. + +```typescript +// src/backend/src/services/calendar.services.ts +import { User, Shop, notGuest } from 'shared'; +import prisma from '../prisma/prisma.js'; +import { + AccessDeniedGuestException, + HttpException +} from '../utils/errors.utils.js'; +import { shopTransformer } + from '../transformers/calendar.transformer.js'; +import { getShopQueryArgs } + from '../prisma-query-args/shop.query-args.js'; +import { userHasPermission } + from '../utils/users.utils.js'; +import { Organization } from '@prisma/client'; + +export default class CalendarService { + /** + * Creates a new shop. + * + * @param submitter the user creating the shop + * @param name the name of the shop + * @param description a description of the shop + * @param dateEstablished when the shop was set up + * @param organization the current organization + * @returns the created Shop + * @throws AccessDeniedGuestException if the + * submitter is a guest + * @throws HttpException if a shop with the same + * name already exists + */ + static async createShop( + submitter: User, + name: string, + description: string, + dateEstablished: Date, + organization: Organization + ): Promise { + // 1. Permission check + if ( + !(await userHasPermission( + submitter.userId, + organization.organizationId, + notGuest + )) + ) { + throw new AccessDeniedGuestException( + 'create shops' + ); + } + + // 2. Business rule validation (inline select) + const duplicate = await prisma.shop.findFirst({ + where: { + organizationId: organization.organizationId, + dateDeleted: null, + name: { equals: name, mode: 'insensitive' } + }, + select: { shopId: true } + }); + + if (duplicate) { + throw new HttpException( + 400, + 'A shop with that name already exists' + ); + } + + // 3. Database write (query args for response) + const created = await prisma.shop.create({ + data: { + name, + description, + dateEstablished, + organizationId: organization.organizationId, + userCreatedId: submitter.userId + }, + ...getShopQueryArgs(organization.organizationId) + }); + + // 4. Transform and return + return shopTransformer(created); + } +} +``` + +**Key rules for services:** + +- Every method MUST be `static async`. +- Every mutation method MUST accept `submitter: User` and `organization: Organization`. +- Every read method MUST accept `organization: Organization` and filter by `organization.organizationId`. +- NEVER return raw Prisma objects. Always pass results through a transformer. +- Throw custom exceptions from `errors.utils.ts` — never throw plain `Error` objects. +- Add JSDoc comments with `@param`, `@returns`, and `@throws` tags. +- Multiple database writes MUST be wrapped in `prisma.$transaction()`. +- Check permissions early, before any database writes. +- ALWAYS filter `dateDeleted: null` on queries at both the top level and within nested includes/selects. +- Deleting an entity MUST be a soft delete (`dateDeleted: new Date()`), never `prisma.*.delete()`. + +For query args and transformer patterns, see the [query-args-and-transformers](./query-args-and-transformers) skill. + +### Step 5: Deciding the Access Level + +Every write endpoint (and some sensitive reads) needs a permission check at the top of the service method. Use `userHasPermission` with the appropriate check function from `shared`: + +```typescript +import { + notGuest, // members and above + isLeadership, // leads and above + isHead, // heads and above + isAdmin // admins and app-admins only +} from 'shared'; + +if ( + !(await userHasPermission( + submitter.userId, + organization.organizationId, + isHead // choose the right level + )) +) { + throw new AccessDeniedAdminOnlyException( + 'create event types' + ); +} +``` + +**How to choose the right level:** + +The role hierarchy from lowest to highest is: Guest → Member → Leadership (leads) → Head → Admin → App Admin. + +- **`notGuest` (members and up):** Most create operations on everyday entities. Members should be able to create things they interact with regularly (e.g., reimbursement requests, schedule confirmations, tasks). All writes should be at least this level — guests NEVER mutate data. +- **`isLeadership` (leads and up):** Creating higher-level entities and editing things the user created. Leads should be able to create basically anything, and edit their own creations. +- **`isHead` (heads and up):** Creating and editing general organizational objects not attached to a specific user (e.g., event types, calendars, shops, machinery). +- **`isAdmin` (admins only):** Org-wide configuration or destructive operations (e.g., deleting event types, managing organization settings, creating projects or work packages without a change request). + +Match the exception class to the level: `AccessDeniedGuestException` for `notGuest`, `AccessDeniedMemberException` for `isLeadership`, `AccessDeniedException` with a descriptive message for `isHead`, `AccessDeniedAdminOnlyException` for `isAdmin`. + +## Error Handling + +Services throw exceptions from `src/backend/src/utils/errors.utils.ts`. The global `errorHandler` middleware catches them. + +| Exception | Status | When to Use | +|-----------|--------|-------------| +| `HttpException(status, msg)` | any | General-purpose with custom status | +| `NotFoundException(name, id)` | 404 | Entity not found | +| `DeletedException(name, id)` | 404 | Entity is soft-deleted | +| `AccessDeniedException(msg?)` | 403 | Generic permission failure | +| `AccessDeniedAdminOnlyException(action)` | 403 | Non-admin attempting admin action | +| `AccessDeniedMemberException(action)` | 403 | Guest/member attempting restricted action | +| `AccessDeniedGuestException(action)` | 403 | Guest attempting non-guest action | +| `InvalidOrganizationException(item)` | 400 | Entity not in current org | + +The `name` parameter for `NotFoundException` and `DeletedException` MUST be one of the values in the `ExceptionObjectNames` type union in `errors.utils.ts`. Add your entity to that type if it's not listed. + +## Validation Helpers + +`src/backend/src/utils/validation.utils.ts` provides reusable validation chains: + +| Helper | Validates | +|--------|-----------| +| `nonEmptyString(body('x'))` | Non-empty string | +| `intMinZero(body('x'))` | Integer ≥ 0, not a string | +| `decimalMinZero(body('x'))` | Decimal ≥ 0 | +| `isDate(body('x'))` | Parseable date string | +| `isOptionalDate(body('x'))` | Optional parseable date | +| `isRole(body('x'))` | Valid `RoleEnum` value | +| `isStatus(body('x'))` | Valid `WbsElementStatus` | +| `isEventStatus(body('x'))` | Valid `Event_Status` | +| `validateInputs` | Runs validation, returns 400 | + +For complex reusable validators, spread them: `...descriptionBulletsValidators`. + +## Key Rules + +- Every controller method MUST pass errors to `next(error)`. +- Every service method MUST filter by `organization.organizationId`. +- Use `GET` for reads, `POST` for all mutations. NEVER use `PUT`, `PATCH`, or `DELETE`. +- NEVER return raw Prisma objects from services. Always use transformers. +- Multiple database writes MUST be wrapped in `prisma.$transaction()`. +- Service and controller classes use `static` methods — never instantiated. +- Always use `.js` extensions in import paths (NodeNext module resolution). +- Import `prisma` from `../prisma/prisma.js`, never from `@prisma/client` directly. +- ALWAYS filter `dateDeleted: null` at both top level and in nested relations. +- Deleting an entity MUST be a soft delete (`dateDeleted: new Date()`). +- Parse date strings to `Date` objects in the controller. + +## Common Mistakes + +- **Handling errors in the controller** instead of calling `next(error)`. +- **Forgetting `organizationId`** in a Prisma query — leaks data across orgs. +- **Using `PUT` or `DELETE` HTTP methods.** Use `POST` for all mutations. +- **Writing business logic in the controller.** Anything beyond request extraction belongs in the service. +- **Forgetting `validateInputs`** as the last middleware before the controller. +- **Not adding your entity to `ExceptionObjectNames`** when using `NotFoundException` or `DeletedException`. +- **Confusing the endpoint URL.** Full path = `index.ts` base path + route path. +- **Forgetting to parse dates in the controller.** Convert with `new Date()` before passing to the service. +- **Forgetting `dateDeleted: null`** on queries or nested relations. + +## Reference Files + +- `src/backend/src/routes/calendar.routes.ts` — Comprehensive route file with many endpoint types +- `src/backend/src/controllers/calendar.controllers.ts` — Clean controller class with consistent try/catch/next +- `src/backend/src/services/calendar.services.ts` — Full-featured service with permissions, org validation, transactions +- `src/backend/src/utils/errors.utils.ts` — Custom exception classes and global error handler +- `src/backend/src/utils/validation.utils.ts` — Shared validation helpers +- `src/backend/index.ts` — Middleware ordering and route registration +- `src/backend/custom.d.ts` — TypeScript augmentation for `currentUser` and `organization` + +## Checklist + +- [ ] Route uses `GET` for reads, `POST` for mutations +- [ ] All body/param/query fields have validation rules +- [ ] `validateInputs` is the last middleware before the controller +- [ ] Full endpoint URL (index.ts base + route path) is correct +- [ ] Controller is `static async` with `try/catch/next(error)` +- [ ] Controller contains NO business logic +- [ ] Date strings parsed to `Date` objects in the controller +- [ ] Service has appropriate permission check (see access level guide) +- [ ] Service filters `organization.organizationId` on all queries +- [ ] Service throws custom exceptions, not plain `Error` +- [ ] Entity name added to `ExceptionObjectNames` if needed +- [ ] All queries filter `dateDeleted: null` at every level +- [ ] Delete operations are soft deletes +- [ ] Service returns transformed shared types (see [query-args-and-transformers](./query-args-and-transformers)) +- [ ] Multiple writes wrapped in `prisma.$transaction()` +- [ ] All imports use `.js` extensions +- [ ] Router registered in `index.ts` (if new feature) + +## Migration Notes + +> New code MUST follow the patterns above. When modifying existing files, update them to match where practical. + +`work-packages.routes.ts` contains one endpoint using the `DELETE` HTTP method (`workPackagesRouter.delete('/:wbsNum/delete', ...)`). This is legacy. The prescribed pattern is `POST` for all mutations including deletions. When touching this endpoint, migrate it to `POST`. diff --git a/docs-site/docs/general-practices/frontend-forms.md b/docs-site/docs/general-practices/frontend-forms.md new file mode 100644 index 0000000000..8c982ae0f6 --- /dev/null +++ b/docs-site/docs/general-practices/frontend-forms.md @@ -0,0 +1,621 @@ +--- +title: Frontend Forms +description: Guide for building forms in FinishLine using React Hook Form with MUI components and the NERFormModal abstraction. Covers useForm setup, Controller wrapping, create vs edit mode, form-modal reset lifecycle, and shared form field components. Use when creating new forms, adding form fields, building create/edit modals, working with React Hook Form, or debugging form state issues. NEVER use useEffect to sync form state. +skill: true +skill_name: frontend-forms +--- + +# Frontend Forms + +> **Summary:** FinishLine forms use React Hook Form with Yup validation, MUI +> components wrapped via `Controller`, and the `NERFormModal` component for +> modal-based forms. The parent component owns the mutation; the form just +> calls `onSubmit` with validated data. + +## Overview + +All forms in FinishLine follow a consistent pattern built on three libraries: +React Hook Form for state management, Yup for schema validation, and MUI for +UI components. The key architectural decision is a strict separation between +the **form component** (which handles layout, validation, and data collection) +and the **parent component** (which owns the mutation hook and handles API +calls). + +For modal-based forms (the most common pattern), FinishLine provides +`NERFormModal` — a wrapper around `NERModal` that handles the form element, +submit-then-reset, and reset-on-close lifecycle automatically. For full-page +forms (like the Work Package editor), the form element is rendered directly. + +React Hook Form's `defaultValues` and `reset` function are the **only** +mechanisms for initializing and updating form state. `useEffect` MUST NEVER +be used to synchronize form fields with props, reset forms, or respond to +data changes. + +## Architecture + +### Modal Form Data Flow + +``` +┌──────────────┐ onSubmit ┌──────────────┐ +│ CreateXModal │◀── (data) ──── │ XFormModal │ +│ or EditXModal│ │ (shared form)│ +├──────────────┤ ├──────────────┤ +│ owns mutation│ │ useForm() │ +│ hook │── defaultValues│ Controller │ +│ passes │── onSubmit ──▶ │ Yup schema │ +│ mutateAsync │ │ NERFormModal │ +└──────────────┘ └──────────────┘ + │ + ▼ + React Query + mutation hook +``` + +### Full-Page Form Data Flow + +``` +┌──────────────┐ mutateAsync ┌──────────────┐ +│ CreateXForm │── + schema ───▶│ XFormView │ +│ or EditXForm │ │ │ +├──────────────┤ ├──────────────┤ +│ owns mutation│ │ useForm() │ +│ fetches data │── defaultValues│
tag │ +│ builds schema│── onSubmit ──▶ │ Controller │ +└──────────────┘ └──────────────┘ +``` + +## File Locations + +- **NERFormModal:** `src/frontend/src/components/NERFormModal.tsx` +- **NERModal (base):** `src/frontend/src/components/NERModal.tsx` +- **NERDraggableFormModal:** `src/frontend/src/components/NERDraggableFormModal.tsx` +- **ReactHookTextField:** `src/frontend/src/components/ReactHookTextField.tsx` +- **ReactHookEditableList:** `src/frontend/src/components/ReactHookEditableList.tsx` +- **Modal forms:** `src/frontend/src/pages/{Feature}/{Components}/XFormModal.tsx` +- **Full-page forms:** `src/frontend/src/pages/{Feature}Form/XFormView.tsx` + +## Core Concepts + +### NERFormModal + +`NERFormModal` wraps `NERModal` and provides automatic form lifecycle +management. It accepts these key props: + +- `reset` — The `reset` function from `useForm`. Called on close AND + after successful submit. +- `handleUseFormSubmit` — The `handleSubmit` function from `useForm`. + Used to wrap the submit handler with validation. +- `onFormSubmit` — Your submit callback. Receives validated form data. +- `formId` — Connects the internal `` to the modal's submit button. + +NERFormModal internally: + +1. Wraps `onFormSubmit` to call `reset()` after the submit callback +2. Calls `reset()` when the modal is closed via `onHide` +3. Renders a `` element with `noValidate` and `e.stopPropagation()` + +### useForm Setup + +Every form calls `useForm` with a Yup resolver and typed `defaultValues`: + +```tsx +import { useForm, Controller } from 'react-hook-form'; +import { yupResolver } from '@hookform/resolvers/yup'; +import * as yup from 'yup'; + +interface MyFormValues { + name: string; + description?: string; + amount: number; + isActive: boolean; +} + +const schema = yup.object().shape({ + name: yup.string().required('Name is required'), + description: yup.string().optional(), + amount: yup.number().required('Amount is required'), + isActive: yup.boolean().required() +}); + +const { + handleSubmit, + control, + reset, + formState: { errors } +} = useForm({ + resolver: yupResolver(schema), + defaultValues: { + name: defaultValues?.name ?? '', + description: defaultValues?.description ?? '', + amount: defaultValues?.amount ?? 0, + isActive: defaultValues?.isActive ?? false + } +}); +``` + +### Controller Pattern for MUI Components + +MUI components are not compatible with `register` because they don't +expose a native `ref`. Use `Controller` to bridge React Hook Form and +MUI: + +```tsx + ( + + )} +/> +{errors.name?.message} +``` + +For checkboxes: + +```tsx + ( + onChange(e.target.checked)} /> + )} +/> +``` + +For `Select`: + +```tsx + ( + + )} +/> +``` + +For `Autocomplete` (multi-select): + +```tsx + ( + opt.label} + isOptionEqualToValue={(opt, val) => opt.id === val.id} + value={memberOptions.filter((o) => value?.includes(o.id))} + onChange={(_, newVal) => onChange(newVal.map((v) => v.id))} + renderInput={(params) => } + /> + )} +/> +``` + +## Step-by-Step: Creating a Modal Form + +### Step 1: Define the Form Values Interface and Schema + +Create the Yup schema and TypeScript interface for your form data. +The interface is used to type `useForm` and the `onSubmit` callback. + +```tsx +// In XFormModal.tsx +interface MyFormValues { + name: string; + code: number; + allowed: boolean; +} + +const schema = yup.object().shape({ + name: yup.string().required('Name is required'), + code: yup.number().typeError('Must be a number').required('Code is required'), + allowed: yup.boolean().required() +}); +``` + +### Step 2: Define the Form Modal Component Props + +The shared form modal accepts: `showModal`, `handleClose`, an optional +`defaultValues` for edit mode, and an `onSubmit` callback. + +```tsx +interface MyFormModalProps { + showModal: boolean; + handleClose: () => void; + defaultValues?: ExistingEntity; // from shared types + onSubmit: (data: MyFormValues) => void; +} +``` + +### Step 3: Set Up useForm with defaultValues + +Initialize `useForm` with `yupResolver` and compute `defaultValues` +from the optional prop. Use `??` to provide empty defaults for create +mode. + +```tsx +const MyFormModal = ({ + showModal, + handleClose, + defaultValues, + onSubmit +}: MyFormModalProps) => { + const toast = useToast(); + + const { + handleSubmit, + control, + reset, + formState: { errors } + } = useForm({ + resolver: yupResolver(schema), + defaultValues: { + name: defaultValues?.name ?? '', + code: defaultValues?.code ?? undefined, + allowed: defaultValues?.allowed ?? false + } + }); +``` + +### Step 4: Define the onFormSubmit Handler + +This wraps the parent's `onSubmit` with error handling. The parent +owns the mutation; this component just passes data up. + +```tsx +const onFormSubmit = async (data: MyFormValues) => { + try { + await onSubmit(data); + } catch (error: unknown) { + if (error instanceof Error) { + toast.error(error.message); + } + } + handleClose(); +}; +``` + +### Step 5: Render NERFormModal with Form Fields + +Pass `reset`, `handleSubmit`, and `onFormSubmit` to NERFormModal. +Use `Controller` to wrap each MUI field. Use `ReactHookTextField` +for simple text inputs. + +```tsx + return ( + reset({ + name: '', + code: undefined, + allowed: false + })} + handleUseFormSubmit={handleSubmit} + onFormSubmit={onFormSubmit} + formId={ + !!defaultValues + ? 'edit-thing-form' + : 'create-thing-form' + } + showCloseButton + > + + + + Name:* + + + + {errors.name?.message} + + + {/* More fields... */} + + + ); +}; +``` + +### Step 6: Create Thin Wrapper Components + +Create `CreateXModal` and `EditXModal` that own the mutation hook +and pass `mutateAsync` as `onSubmit`: + +**CreateXModal.tsx:** + +```tsx +const CreateThingModal = ({ showModal, handleClose }: CreateThingModalProps) => { + const { isLoading, isError, error, mutateAsync } = useCreateThing(); + + if (isError) return ; + if (isLoading) return ; + + return ; +}; +``` + +**EditXModal.tsx:** + +```tsx +const EditThingModal = ({ showModal, handleClose, thing }: EditThingModalProps) => { + const { isLoading, isError, error, mutateAsync } = useEditThing(thing.id); + + if (isError) return ; + if (isLoading) return ; + + return ; +}; +``` + +## Step-by-Step: Creating a Full-Page Form + +Full-page forms (like Work Package create/edit) skip NERFormModal and +render the `` element directly. The pattern is similar but uses +`PageLayout` instead of a modal. + +### Step 1: Create the Form View Component + +The form view accepts `defaultValues`, `onSubmit` (the mutation), +and a Yup `schema` from the parent: + +```tsx +const ThingFormView: React.FC = ({ exitActiveMode, onMutate, defaultValues, schema, breadcrumbs }) => { + const { + handleSubmit, + control, + formState: { errors } + } = useForm({ + resolver: yupResolver(schema), + defaultValues: { + name: defaultValues?.name ?? '' + // ... + } + }); + + const onSubmit = async (data: ThingFormPayload) => { + try { + await onMutate(data); + exitActiveMode(); + } catch (e) { + if (e instanceof Error) toast.error(e.message); + } + }; + + return ( + { + e.preventDefault(); + e.stopPropagation(); + handleSubmit(onSubmit)(e); + }} + noValidate + > + {/* Form fields using Controller */} + + ); +}; +``` + +### Step 2: Create the Wrapper Component + +The wrapper fetches data and owns the mutation: + +```tsx +const CreateThingForm: React.FC = () => { + const { mutateAsync } = useCreateThing(); + const history = useHistory(); + + const schema = yup.object().shape({ + name: yup.string().required('Name is required') + }); + + return ( + history.push(routes.THINGS)} + schema={schema} + breadcrumbs={[{ name: 'Things', route: routes.THINGS }]} + /> + ); +}; +``` + +## Shared Form Components + +### ReactHookTextField + +A pre-built `Controller`-wrapped `TextField`. Use for simple text, +number, and multiline inputs: + +```tsx +import ReactHookTextField from '../../components/ReactHookTextField'; + +; +``` + +### ReactHookEditableList + +For dynamic lists of items using `useFieldArray`. Items can be added +and removed: + +```tsx +import ReactHookEditableList from '../../components/ReactHookEditableList'; + +const { fields, append, remove } = useFieldArray({ + control, + name: 'bullets' +}); + +; +``` + +Each item in the field array MUST have a `detail` property: + +```tsx +append({ bulletId: -1, detail: '' }); +``` + +## Key Rules + +- `useForm` MUST always be called with `defaultValues`. NEVER + initialize a form without defaults — it causes uncontrolled-to- + controlled component warnings and broken reset behavior. + +- `useEffect` MUST NEVER be used to synchronize form state, reset + forms, or respond to prop changes in form components. React Hook + Form's `defaultValues` and `reset()` handle all of these cases. + +- The form component MUST NOT own the mutation hook. The parent + (CreateXModal / EditXModal) owns the mutation and passes + `mutateAsync` as the `onSubmit` prop. + +- The `reset` prop passed to `NERFormModal` MUST reset to empty/default + values (for create mode), NOT to `defaultValues`. NERFormModal calls + `reset()` both on close and after submit, so it needs to clear the + form for the next use. + +- Always use `e.stopPropagation()` in form submit handlers to prevent + event bubbling when forms are nested inside modals or other forms. + +- Use `noValidate` on all `
` elements to let Yup handle + validation instead of browser-native validation. + +- The `formId` prop on NERFormModal MUST match the `id` of the + internal `` element (NERFormModal handles this automatically). + +- Create/Edit mode is determined by the presence of `defaultValues`. + Use `!!defaultValues` to toggle titles and form IDs. + +- Yup schemas can be defined either at module level (for static + schemas) or inside the component (when the schema depends on props + or state). + +## Common Mistakes + +- **Using `useEffect` to sync form state with props.** This causes + stale data, infinite loops, and race conditions. Use + `defaultValues` in `useForm()` for initial values. If you need to + reset to new values after mount, call `reset(newValues)` directly + in a handler — never in a `useEffect`. + +- **Putting the mutation hook inside the form modal.** The form modal + should be reusable for create and edit. The mutation belongs in the + thin wrapper component (CreateXModal or EditXModal). + +- **Forgetting to pass `reset` to NERFormModal.** Without it, closing + and reopening the modal will show stale data from the previous + session. + +- **Passing `defaultValues` directly as the NERFormModal `reset` + prop.** The `reset` prop should reset to empty/blank values so the + form is clean when reused. Pass `() => reset({ name: '', ... })`. + +- **Using `register` with MUI components.** MUI components need + `Controller` because they don't expose native input refs. Only + use `register` with plain HTML inputs or inside + `ReactHookEditableList`. + +- **Forgetting `e.stopPropagation()` on form submit.** Without this, + submitting a form inside a modal can trigger parent form handlers, + leading to double submissions or unexpected behavior. + +## Reference Files + +These files demonstrate the prescribed patterns well: + +- `src/frontend/src/components/NERFormModal.tsx` — The core form + modal abstraction with reset-on-close and submit-then-reset +- `src/frontend/src/pages/AdminToolsPage/FinanceConfig/AccountCodeFormModal.tsx` + — Clean example of a shared create/edit form modal with Yup, + Controller, and ReactHookTextField +- `src/frontend/src/pages/AdminToolsPage/FinanceConfig/CreateAccountCodeModal.tsx` + — Clean create wrapper (mutation owner) +- `src/frontend/src/pages/AdminToolsPage/FinanceConfig/EditAccountCodeModal.tsx` + — Clean edit wrapper (passes `defaultValues`) +- `src/frontend/src/pages/FinancePage/FinanceComponents/VendorFormModal.tsx` + — Good example with multiple field types (text, checkbox, + autocomplete multi-select) +- `src/frontend/src/pages/WorkPackageForm/WorkPackageFormView.tsx` + — Full-page form pattern with `useFieldArray` +- `src/frontend/src/components/ReactHookTextField.tsx` — Shared + Controller-wrapped TextField component +- `src/frontend/src/components/ReactHookEditableList.tsx` — Shared + dynamic list component using `useFieldArray` + +## Checklist + +- [ ] Form uses `useForm` with `yupResolver` and typed `defaultValues` +- [ ] All MUI components are wrapped with `Controller` (not `register`) +- [ ] Yup schema validates all required fields with clear error messages +- [ ] `NERFormModal` receives `reset`, `handleUseFormSubmit`, and `onFormSubmit` +- [ ] `reset` prop resets to empty values, not to `defaultValues` +- [ ] Form component does NOT own the mutation hook +- [ ] Create wrapper passes `mutateAsync` as `onSubmit` (no `defaultValues`) +- [ ] Edit wrapper passes `mutateAsync` AND entity as `defaultValues` +- [ ] Create vs edit title/formId uses `!!defaultValues` check +- [ ] `showCloseButton` is set on the NERFormModal +- [ ] No `useEffect` is used for form state synchronization +- [ ] Form submit handler uses `e.stopPropagation()` +- [ ] `` element has `noValidate` attribute +- [ ] Error messages display via `` + +## Migration Notes + +> This section describes how this pattern differs from older code in the +> codebase. New code MUST follow the patterns above. When modifying existing +> files, update them to match these patterns where practical. + +Some existing form components use `useEffect` to synchronize form state +with loaded data (e.g., `EventModal.tsx` uses `useEffect` to populate +Autocomplete selections from `initialValues` when `users` data loads). +The prescribed pattern avoids this entirely by computing all initial +values in the `defaultValues` object passed to `useForm`. When modifying +these files, replace `useEffect`-based synchronization with proper +`defaultValues` computation or direct `reset()` calls in event handlers. + +Some older form modals also maintain parallel `useState` for values that +should be managed by React Hook Form (e.g., separate `useState` for +selected members alongside the form's member IDs). New forms MUST keep +all form state within React Hook Form — use `watch()` to read values +and `setValue()` to write them programmatically when needed. diff --git a/docs-site/docs/general-practices/frontend-hooks-and-apis.md b/docs-site/docs/general-practices/frontend-hooks-and-apis.md new file mode 100644 index 0000000000..8c34d5ffcb --- /dev/null +++ b/docs-site/docs/general-practices/frontend-hooks-and-apis.md @@ -0,0 +1,471 @@ +--- +title: Frontend Hooks and APIs +description: Guide for creating React Query hooks and Axios API client functions in FinishLine. Covers query hooks, mutation hooks, API functions, query keys, cache invalidation, toast notifications, and frontend transformers. Use when creating new hooks, adding API calls, writing query or mutation hooks, working with React Query, implementing cache invalidation, or when asked how frontend data fetching works. +skill: true +skill_name: frontend-hooks-and-apis +--- + +# Frontend Hooks and API Client Functions + +> **Summary:** All server state in FinishLine flows through React Query hooks backed by Axios API functions. Query hooks fetch data, mutation hooks write data, and both follow strict patterns for cache invalidation and toast notifications. + +## Overview + +FinishLine uses React Query v3 for all server state management. Every API interaction follows a two-layer pattern: a **hook** (in `src/frontend/src/hooks/`) wraps a React Query `useQuery` or `useMutation` call, which delegates the actual HTTP request to an **API function** (in `src/frontend/src/apis/`). This separation keeps hooks focused on caching/state concerns and API functions focused on HTTP concerns. + +The data flow for a **query** (read): + +``` +Component → useQuery hook → API function → Axios GET → Backend + ↓ +Component ← hook returns { data, isLoading } ← Axios response (transformed) +``` + +The data flow for a **mutation** (write): + +``` +Component → calls mutateAsync → useMutation hook → API function → Axios POST → Backend + ↓ +Component ← promise resolves ← hook invalidates cache + shows toast +``` + +A custom Axios instance (`src/frontend/src/utils/axios.ts`) automatically attaches the `organizationId` header on every request and converts backend error responses into JavaScript `Error` objects with meaningful messages. + +## Architecture + +``` +┌──────────────┐ ┌──────────────┐ +│ Component │ │ useToast() │ +│ (page/modal)│ │ (context) │ +└──────┬───────┘ └──────▲───────┘ + │ calls hook │ toast.success / error + ▼ │ +┌──────────────────────────────────┐ +│ Hook (useQuery / useMutation) │ +│ - query key management │ +│ - cache invalidation │ +│ - toast on success/error │ +│ - extracts .data from response │ +└──────────────┬───────────────────┘ + │ calls API fn + ▼ +┌──────────────────────────────────┐ +│ API Function (Axios call) │ +│ - builds URL via apiUrls │ +│ - sets transformResponse │ +│ - returns AxiosResponse │ +└──────────────┬───────────────────┘ + │ HTTP request + ▼ +┌──────────────────────────────────┐ +│ Backend (Express endpoint) │ +└──────────────────────────────────┘ +``` + +## File Locations + +- **Hooks:** `src/frontend/src/hooks/{feature}.hooks.ts` +- **API functions:** `src/frontend/src/apis/{feature}.api.ts` +- **Frontend transformers:** `src/frontend/src/apis/transformers/{feature}.transformer.ts` +- **URL builder:** `src/frontend/src/utils/urls.ts` (the `apiUrls` object) +- **Axios instance:** `src/frontend/src/utils/axios.ts` +- **Shared types:** `src/shared/src/types/{feature}-types.ts` +- **Toast hook:** `src/frontend/src/hooks/toasts.hooks.ts` + +Naming conventions: hook files and API files MUST use the same feature name prefix. If the hooks file is `calendar.hooks.ts`, the API file is `calendar.api.ts`. + +## Query Keys + +Query keys are the backbone of React Query's caching and invalidation system. Every query MUST have a key that uniquely identifies the data it fetches, and mutation hooks MUST invalidate the correct keys so the UI stays in sync. + +### Key Structure + +Query keys are arrays. The first element identifies the entity type, and subsequent elements narrow the scope: + +```typescript +// List query — base key +useQuery(['events'], ...) + +// Detail query — appends ID +useQuery(['events', id], ...) + +// Filtered query — appends filter params +useQuery( + ['filter-events', filterArgs], + ... +) + +// Scoped detail — appends multiple segments +useQuery( + ['events', id, 'with-members'], + ... +) +``` + +For keys that are reused across multiple hooks or need to be imported by other files for cross-feature invalidation, declare them as named constants at the top of the hooks file: + +```typescript +export const EVENT_KEY = ['events'] as const; +export const EVENT_TYPE_KEY = ['event-types'] as const; +``` + +This is optional — inline arrays like `['events']` are equally valid. The important thing is that keys are **consistent** so that invalidation works correctly. + +### Key Rules + +- Detail keys MUST include the entity ID as the second element +- Filter/variant keys MUST include the filter params or variant name +- Keys MUST use lowercase hyphen-separated strings (e.g., `'filter-events'`, `'event-types'`) +- NEVER use the same key for two different queries +- If a key is used for invalidation in another hook file, export it as a named constant + +## Step-by-Step: Adding a New Query Hook + +### Step 1: Add the URL to `apiUrls` + +In `src/frontend/src/utils/urls.ts`, add a URL builder function and export it: + +```typescript +// Near other calendar endpoints +const calendarShops = () => `${calendar()}/shops`; + +// In the apiUrls export object +export const apiUrls = { + // ...existing urls + calendarShops +}; +``` + +### Step 2: Write the API Function + +In `src/frontend/src/apis/{feature}.api.ts`: + +```typescript +import axios from '../utils/axios'; +import { apiUrls } from '../utils/urls'; +import { Shop } from 'shared'; + +export const getAllShops = () => { + return axios.get(apiUrls.calendarShops(), { + transformResponse: (data) => JSON.parse(data) as Shop[] + }); +}; +``` + +Key rules for API functions: + +- ALWAYS return the `AxiosResponse` directly (i.e., `return axios.get(...)` — do NOT extract `.data` inside the API function) +- Use `transformResponse` to parse JSON and apply frontend transformers when the response contains dates or nested objects that need transformation +- Import types from `shared`, not from local definitions +- Function names MUST match the HTTP semantics: `get*` for GET, `post*` / `create*` / `edit*` / `delete*` for POST/PUT/DELETE + +### Step 3: Write the Frontend Transformer (if needed) + +If the response contains `Date` fields (which arrive as strings from JSON) or nested objects that need transformation, create a transformer in `src/frontend/src/apis/transformers/{feature}.transformer.ts`: + +```typescript +import { Event } from 'shared'; + +export const eventTransformer = (event: Event): Event => { + if (!event || !event.scheduledTimes) return event; + return { + ...event, + dateCreated: new Date(event.dateCreated), + scheduledTimes: event.scheduledTimes.map((slot) => ({ + ...slot, + startTime: new Date(slot.startTime), + endTime: new Date(slot.endTime) + })) + }; +}; +``` + +Then use it in the API function's `transformResponse`: + +```typescript +import { eventTransformer } from './transformers/calendar.transformer'; + +export const getAllEvents = () => { + return axios.get(apiUrls.calendarEvents(), { + transformResponse: (data) => JSON.parse(data).map(eventTransformer) + }); +}; +``` + +See the [query-args-and-transformers skill](../../general-practices/query-args-and-transformers/SKILL.md) for detailed transformer patterns. + +### Step 4: Write the Query Hook + +In `src/frontend/src/hooks/{feature}.hooks.ts`: + +```typescript +import { useQuery } from 'react-query'; +import { Shop } from 'shared'; +import { getAllShops } from '../apis/calendar.api'; + +export const useAllShops = () => + useQuery(['shops'], async () => { + const { data } = await getAllShops(); + return data; + }); +``` + +For detail queries that take an ID parameter, use the `enabled` option to prevent fetching when the ID is undefined: + +```typescript +export const useSingleEvent = (id?: string) => { + return useQuery( + ['events', id], + async () => { + const { data } = await getSingleEvent(id!); + return data; + }, + { enabled: !!id } + ); +}; +``` + +### Query Hook Rules + +- The query function MUST destructure `{ data }` from the API response and return `data` +- Type the hook as `useQuery` +- Use `enabled` to conditionally skip queries when required params are missing +- Use `keepPreviousData: true` for filter/pagination queries to avoid UI flicker + +## Step-by-Step: Adding a New Mutation Hook + +### Step 1: Add the URL and API Function + +Same as query steps 1-2, but using `axios.post` (or `.put`, `.delete`): + +```typescript +export const postCreateShop = (payload: { name: string; description: string }) => { + return axios.post(apiUrls.calendarCreateShop(), payload, { + transformResponse: (data) => JSON.parse(data) as Shop + }); +}; +``` + +### Step 2: Write the Mutation Hook + +Every mutation hook MUST: + +1. Get the query client for cache invalidation +2. Return `useMutation` with explicit type parameters +3. Invalidate all relevant query keys on success +4. Show a toast on both success and error + +```typescript +import { useMutation, useQueryClient } from 'react-query'; +import { Shop } from 'shared'; +import { postCreateShop } from '../apis/calendar.api'; +import { useToast } from './toasts.hooks'; + +export const useCreateShop = () => { + const queryClient = useQueryClient(); + const toast = useToast(); + return useMutation( + async (payload) => { + const { data } = await postCreateShop(payload); + return data; + }, + { + onSuccess: () => { + queryClient.invalidateQueries(['shops']); + toast.success('Shop created successfully!'); + }, + onError: (error) => { + toast.error(error.message, 5000); + } + } + ); +}; +``` + +### Step 3: Use the Hook in a Component + +Components call mutation hooks and use `mutateAsync` for async/await control: + +```typescript +const CreateShopModal: React.FC = ({ open, onClose }) => { + const { mutateAsync: createShop } = useCreateShop(); + + const handleSubmit = async (payload: ShopFormData) => { + try { + await createShop(payload); + onClose(); + } catch (e) { + // Error toast is handled by the hook's onError. + // Re-throw only if the component needs to react + // further (e.g., keep modal open). + } + }; + + return ; +}; +``` + +### Mutation Keys + +Unlike query hooks, mutation hooks do NOT require an explicit mutation key. You can optionally add one as the first argument to `useMutation` if you need to reference the mutation elsewhere (e.g., for `useMutationState` or devtools tracking): + +```typescript +// Without mutation key (standard) +useMutation( + async (payload) => { ... }, + { onSuccess: () => { ... } } +); + +// With optional mutation key +useMutation( + ['shops', 'create'], + async (payload) => { ... }, + { onSuccess: () => { ... } } +); +``` + +### Mutation Type Parameters + +`useMutation` takes three type parameters: ``: + +- `TData` — the type returned by the mutation function (what the backend sends back) +- `TError` — always `Error` +- `TVariables` — the type of the argument passed to `mutateAsync(arg)` + +```typescript +useMutation(...); +// ^TData ^TError ^TVariables +``` + +### Cache Invalidation Rules + +Invalidation MUST cover all queries that could be affected by the mutation: + +- **Create** → invalidate the list key (`['shops']`) and any filtered variants (`['filter-shops']`) +- **Edit** → invalidate both the list key AND the specific detail key (`['shops', id]`) +- **Delete** → invalidate the list key and any filtered variants + +For cross-feature invalidation, import keys from other hook files: + +```typescript +import { EVENT_KEY } from './calendar.hooks'; + +export const useDeleteProject = () => { + const queryClient = useQueryClient(); + const toast = useToast(); + return useMutation<{ message: string }, Error, string>( + async (projectId) => { + const { data } = await deleteProject(projectId); + return data; + }, + { + onSuccess: () => { + queryClient.invalidateQueries(['projects']); + queryClient.invalidateQueries(EVENT_KEY); + toast.success('Project deleted successfully!'); + }, + onError: (error) => { + toast.error(error.message, 5000); + } + } + ); +}; +``` + +### Mutations Without Cache Invalidation + +Some mutations don't affect cached data (e.g., file uploads, Slack notifications). These still MUST show toasts but can skip invalidation: + +```typescript +export const useSlackUpcomingDeadlines = () => { + const toast = useToast(); + return useMutation<{ message: string }, Error, Date>( + async (deadline) => { + const { data } = await slackUpcomingDeadlines(deadline); + return data; + }, + { + onSuccess: () => { + toast.success('Deadlines sent to Slack!'); + }, + onError: (error) => { + toast.error(error.message, 5000); + } + } + ); +}; +``` + +## Toast Notifications + +The `useToast` hook (from `src/frontend/src/hooks/toasts.hooks.ts`) provides four methods: + +```typescript +const toast = useToast(); +toast.success('Created successfully!'); +toast.error('Something went wrong', 5000); +toast.info('Processing...'); +toast.warning('This action is irreversible'); +``` + +The second argument is an optional `autoHideDuration` in milliseconds. Error toasts SHOULD use `5000` to give users time to read the error. Success toasts use the default duration (no second argument). + +### Toast Message Conventions + +- **Success**: Past-tense action description — `'Shop created successfully!'`, `'Event updated successfully!'` +- **Error**: Use `error.message` from the caught error, which contains the backend's error message. Fall back to a generic message: `'Failed to create shop'` + +## Key Rules + +- Every query MUST have a key that uniquely identifies its data; use named constants for keys shared across files +- API functions MUST return `AxiosResponse` — NEVER extract `.data` inside the API function +- Query hooks MUST destructure `{ data }` from the API response +- Every mutation hook MUST call `useToast()` and show toasts in `onSuccess` and `onError` +- Every mutation hook MUST invalidate all relevant query keys on success +- Mutation hooks MUST return the `useMutation` result directly (the component uses `mutateAsync`) +- Types for API responses MUST come from the `shared` package +- Payload/input types that are unique to the frontend (e.g., form-specific types) MAY be defined in the hooks or API file + +## Common Mistakes + +- **Extracting `.data` inside the API function** — This breaks the pattern and makes the return type ambiguous. API functions MUST return `AxiosResponse`. The hook extracts `.data`. +- **Forgetting `transformResponse` for date fields** — JSON serialization turns `Date` objects into strings. Any response with date fields MUST use a transformer in `transformResponse`. +- **Using a plain string as a query key** — `useQuery('events', ...)` is fragile and doesn't support partial invalidation. Always use an array: `useQuery(['events'], ...)` or `useQuery(['events', id], ...)`. +- **Not invalidating filtered/variant queries** — If you have both `['events']` and a filter query (`['filter-events', args]`), a mutation that changes events MUST invalidate both. +- **Handling toasts in the component instead of the hook** — New code MUST handle toasts in the hook's `onSuccess`/`onError`. Components should NOT call `toast.success/error` for standard mutation outcomes. +- **Adding unnecessary mutation keys** — Mutation keys are optional and only needed if you have a specific use case for them. Don't add them by default. + +## Reference Files + +These files demonstrate the patterns well: + +- `src/frontend/src/hooks/calendar.hooks.ts` — Comprehensive example with query hooks, mutation hooks, query key exports, and cross-feature invalidation +- `src/frontend/src/apis/calendar.api.ts` — API functions with `transformResponse` and transformer usage +- `src/frontend/src/hooks/work-packages.hooks.ts` — Query hooks with parameter-based keys and mutation hooks +- `src/frontend/src/apis/work-packages.api.ts` — API functions using `workPackageTransformer` in `transformResponse` +- `src/frontend/src/apis/transformers/calendar.transformer.ts` — Frontend transformers for date conversion and nested object handling +- `src/frontend/src/hooks/toasts.hooks.ts` — The toast hook API +- `src/frontend/src/pages/CalendarPage/Components/CreateEventModal.tsx` — Example of consuming a mutation hook in a component + +## Checklist + +- [ ] Query keys are arrays that uniquely identify the data being fetched +- [ ] API function returns `AxiosResponse` (not extracted `.data`) +- [ ] Hook destructures `{ data }` from the API response +- [ ] `transformResponse` is set with appropriate transformer for responses containing dates +- [ ] Query hooks use `enabled` when parameters may be undefined +- [ ] Mutation hooks call `useToast()` and show toasts in `onSuccess` and `onError` +- [ ] Mutation hooks invalidate all affected query keys (list, detail, filtered variants) +- [ ] Response types are imported from `shared` +- [ ] URL is added to `apiUrls` in `src/frontend/src/utils/urls.ts` +- [ ] Hook and API files share the same feature-name prefix + +## Migration Notes + +> This section describes how this pattern differs from older code in the codebase. New code MUST follow the patterns above. When modifying existing files, update them to match these patterns where practical. + +**Toast notifications:** Many existing mutation hooks (e.g., `useCreateShop`, `useEditCalendar` in `calendar.hooks.ts`) do not include toast notifications. Instead, toasts were handled at the component level. The prescribed pattern moves toasts into the hook's `onSuccess`/`onError` callbacks so that every consumer of the hook gets consistent feedback without duplicating toast logic. When adding new mutations, always include toasts in the hook. When modifying existing mutation hooks, add `useToast()` and the `onSuccess`/`onError` toast callbacks. + +**API function return values:** Some existing API functions (e.g., `postCreateMachinery`, `postEditMachinery` in `calendar.api.ts`) extract `.data` from the Axios response and return the raw data instead of the `AxiosResponse`. The prescribed pattern is for API functions to always return `AxiosResponse`. When touching existing API functions that extract `.data`, refactor them to return the full response and update the corresponding hook to extract `.data`. + +**Mutation keys:** Some existing mutation hooks include an explicit mutation key as the first argument to `useMutation`. This is optional — new code does not need mutation keys unless there is a specific reason (e.g., tracking mutation state externally). Either approach is fine. diff --git a/docs-site/docs/general-practices/postman-api-testing.md b/docs-site/docs/general-practices/postman-api-testing.md new file mode 100644 index 0000000000..c467565f76 --- /dev/null +++ b/docs-site/docs/general-practices/postman-api-testing.md @@ -0,0 +1,321 @@ +--- +title: Postman API Testing +description: Guide for using Postman to test and interact with the FinishLine API during development. Use when testing API endpoints, debugging backend issues, verifying request/response formats, or when asked how to use Postman with the local development environment. +skill: false +--- + +# Postman API Testing + +> **Summary:** Postman enables developers to test API endpoints locally during development. This guide covers setup, authentication, common workflows, and troubleshooting for the FinishLine API running on localhost:3001. + +## Overview + +Postman is an API development tool that allows you to make HTTP requests to the FinishLine backend without needing the frontend interface. This is particularly useful for: + +- Testing new endpoints during development +- Debugging backend issues in isolation +- Verifying request and response formats +- Exploring available API data without UI constraints + +All API requests in local development target `http://localhost:3001`, which is the Express server running on your machine. Many endpoints require authentication using a user ID obtained from the `/users` endpoint. + +## Prerequisites + +Before you begin, ensure you have: + +- [Postman](https://www.postman.com/downloads/) installed +- The FinishLine backend running locally +- The PostgreSQL database running in Docker with seeded data + +## Verifying the API is Running + +Before making requests, confirm the backend is accessible: + +1. Start the backend server if not already running: + + ```bash + yarn backend:dev + ``` + +2. The console should show the server listening on port 3001 + +3. Make a test request to the base URL in Postman: `GET http://localhost:3001` + +If you receive a "Welcome to NER" message, your backend is running and listening on port 3001. This is also the default message you will see if the router cannot resolve the url you requested, so if you get this while trying to test an endpoint it is likely that you have a typo in the url or are using the wrong HTTP method (e.g. POST instead of GET). + +## Base URL + +All API requests in local development should be made to: + +``` +http://localhost:3001 +``` + +This is the Express server listening for HTTP requests. The backend handles routing, authentication, and business logic before querying the PostgreSQL database. + +## Authentication + +Many endpoints in the FinishLine API require authentication to enforce permission checks and organization scoping. Here's how to authenticate your Postman requests: + +### Step 1: Get a User ID + +First, fetch a user from the `/users` endpoint: + +1. Create a new GET request in Postman +2. Enter URL: `http://localhost:3001/users` +3. Click **Send** +4. The response contains an array of users with their `userId` fields +5. Copy a `userId` from any user in the response (typically a string like `"abc-123-def"`) + +### Step 2: Add Authorization Header + +For endpoints requiring authentication: + +1. Navigate to the **Headers** tab in your request +2. Add a new header with: + - **Key:** `authorization` + - **Value:** `` +3. Send your request + +Without proper authorization, protected endpoints will return `401 Unauthorized` or `403 Forbidden` responses depending on the permission level required. + +## Common Workflows + +### Fetching All Users + +**Endpoint:** `GET http://localhost:3001/users` + +**Purpose:** Retrieve all users in the system. Use this to find user IDs for authentication in other requests. + +**Authentication:** Not required + +**Steps:** + +1. Create a new request in Postman +2. Set method to **GET** using the dropdown menu +3. Enter URL: `http://localhost:3001/users` +4. Click **Send** + +**Response:** Array of user objects with `userId`, `firstName`, `lastName`, `email`, and role information. + +### Fetching All Projects + +**Endpoint:** `GET http://localhost:3001/project` + +**Purpose:** Retrieve all projects in the system. Useful for finding existing project data, WBS numbers, or materials associated with projects. + +**Authentication:** Check the route definition to confirm if required + +**Steps:** + +1. Create a new request +2. Set method to **GET** +3. Enter URL: `http://localhost:3001/project` +4. Add authorization header if needed (see Authentication section) +5. Click **Send** + +**Response:** Array of project objects with details like `projectId`, `name`, `wbsNum`, `status`, `teams`, and nested data. + +### Making Authenticated Requests + +For any endpoint that requires authentication: + +1. Fetch a user ID from `GET /users` (see above) +2. Add the `authorization` header with the user ID as the value +3. Make your request normally + +If you forget authorization on a protected route, the response will include an error message indicating permission denied or unauthorized access. + +### Creating or Updating Data (POST Requests) + +When testing endpoints that create or modify data: + +1. Set request method to **POST** +2. Add authentication header with a valid user ID +3. Navigate to the **Body** tab +4. Select **raw** and **JSON** format from the dropdown +5. Enter the request payload as valid JSON +6. Click **Send** + +Example JSON body structure (varies by endpoint): + +```json +{ + "name": "New Project", + "description": "Project description", + "leadId": "user-id-here" +} +``` + +Refer to the backend route validation rules in `src/backend/src/routes/` to determine required fields and formats. + +## Using Postman Features + +### Request Type Selection + +The dropdown menu to the left of the URL field allows you to select the HTTP request method. FinishLine follows this convention: + +- **GET** — Retrieve data (read operations) +- **POST** — Create new data, update existing data, or delete data + +Note: FinishLine does not use `PUT`, `PATCH`, or `DELETE` HTTP methods. All mutations use `POST`. + +### Key Tabs in Postman + +Postman provides several tabs for configuring requests: + +- **Params** — Add query parameters to your URL (e.g., `?limit=10&offset=0`) +- **Authorization** — Alternative way to set auth (use Headers tab for FinishLine) +- **Headers** — Add HTTP headers like `authorization`, `Content-Type`, `organizationId` +- **Body** — Include request payload for POST requests (select raw → JSON format) + +## Finding Endpoint URLs + +To discover available endpoints and their paths: + +1. **Check route files:** Backend routes are defined in `src/backend/src/routes/{feature}.routes.ts` +2. **Combine base paths:** The full URL is `index.ts` base path + route path + - Example: If `index.ts` has `app.use('/calendar', calendarRouter)` and the route defines `POST /shop/create`, the full endpoint is `POST /calendar/shop/create` +3. **Review validation:** Route files show which fields are required and their validation rules using `express-validator` + +## Organization Scoping + +FinishLine is a multi-tenant application. Most endpoints filter data by `organizationId`. In local development with seed data, the organization ID is typically included automatically via middleware. + +If an endpoint requires an explicit `organizationId` header: + +1. Go to the **Headers** tab +2. Add key: `organizationId` +3. Set value to a valid organization ID (check your seed data or database) + +## Troubleshooting + +### "Welcome to NER" Message + +**Problem:** You receive a plain text "Welcome to NER" response. + +**Cause:** The endpoint URL is incorrect or the route doesn't exist. This is the default response when Express can't find a matching route handler. + +**Solution:** + +- Double-check the endpoint URL for typos +- Verify the HTTP method matches the route definition (GET vs POST) +- Confirm the route is registered in `src/backend/index.ts` +- Check that the feature router is imported and mounted on the correct base path + +### Connection Refused or Network Error + +**Problem:** Postman cannot connect to `http://localhost:3001`. + +**Cause:** The backend server is not running. + +**Solution:** + +- Start the backend: `yarn backend:dev` or `yarn start` +- Verify the console shows "Server listening on port 3001" +- Check no other process is using port 3001 +- Wait a few seconds for the server to fully start after running the command + +### 401 Unauthorized or 403 Forbidden + +**Problem:** The endpoint returns a 401 or 403 error. + +**Cause:** Missing or invalid authentication, or insufficient permissions. + +**Solution:** + +- Ensure you've added the `authorization` header with a valid user ID +- Verify the user ID exists in the database (check `/users` response) +- Confirm the user has sufficient permissions for the operation (check the service method's permission check) +- Try using a different user with higher privileges (e.g., an admin user) + +### 400 Bad Request + +**Problem:** The endpoint returns a 400 error with validation messages. + +**Cause:** The request payload doesn't match the validation rules defined in the route. + +**Solution:** + +- Check the route file (`src/backend/src/routes/`) for validation rules +- Verify all required fields are present in the request body +- Ensure field types match expectations (string, number, date, boolean) +- Check for typos in field names +- Review the error response for specific validation failure details + +### Date Format Issues + +**Problem:** Date fields are rejected or cause errors. + +**Cause:** Invalid date string format. + +**Solution:** + +- Use ISO 8601 date format: `"2025-02-16T12:00:00.000Z"` +- Or use a simpler format: `"2025-02-16"` +- Avoid relative dates like "yesterday" or "last week" +- The backend controller parses date strings with `new Date()`, so any format recognized by JavaScript's Date constructor works + +### Empty or Unexpected Response + +**Problem:** The endpoint returns 200 OK but the data is empty or not what you expected. + +**Cause:** Data may be filtered by organization scope, soft-deleted, or the query returned no matches. + +**Solution:** + +- Check the database for relevant data: `yarn prisma:studio` +- Verify `dateDeleted` is `null` on the records you expect to see +- Confirm the records belong to the organization you're querying +- Review the service method's query filters and transformers + +## Available Endpoints Reference + +This table lists some core endpoints available in the FinishLine API. For a complete list, review the route files in `src/backend/src/routes/`. + +| Endpoint | Method | Description | Auth Required | +| ---------- | ------ | ----------------------------------------- | ------------- | +| `/users` | GET | Fetch all users with roles and settings | False | +| `/project` | GET | Fetch all projects with WBS and team data | True | + +_Note: This table is incomplete. When discovering new endpoints, add them here with their method, purpose, and authentication requirements._ + +## Key Rules + +- The base URL is always `http://localhost:3001` for local development +- Use **GET** for reads and **POST** for all mutations (create, update, delete) +- Authentication uses the `authorization` header with a user ID value +- Fetch user IDs from the `/users` endpoint before testing protected routes +- Full endpoint URLs combine the base path from `index.ts` and the route path +- Expect "Welcome to NER" for non-existent or incorrectly typed endpoints +- Validate request payloads against the route's `express-validator` rules +- Organization scoping is enforced — data is filtered by `organizationId` + +## Common Mistakes + +- **Not starting the backend server** before making requests +- **Forgetting the authorization header** on protected endpoints +- **Using incorrect HTTP methods** (e.g., PUT or DELETE instead of POST) +- **Mistyping the endpoint URL** (check the full path: base + route) +- **Not checking route validation rules** before constructing POST request bodies +- **Assuming all endpoints require authentication** — check the route definition +- **Ignoring 400 error details** — the response usually explains what's invalid + +## Reference Files + +- `src/backend/index.ts` — Route registration and middleware setup +- `src/backend/src/routes/{feature}.routes.ts` — Route definitions with HTTP methods and validation rules +- `src/backend/src/controllers/{feature}.controllers.ts` — Request handling logic +- `src/backend/src/services/{feature}.services.ts` — Business logic and permission checks + +## Tips for Efficient Testing + +- **Save requests in collections:** Organize related endpoints into Postman collections for easy reuse +- **Use environments:** Create a Postman environment with variables like `baseUrl` and `userId` to avoid repetitive typing +- **Inspect responses:** Check the response status, headers, and body to verify expected behavior +- **Test edge cases:** Try invalid inputs, missing fields, and unauthorized access to verify error handling +- **Review console logs:** The backend terminal shows request logs and error stack traces + +## Contributing to This Documentation + +If you discover additional endpoints, common workflows, or troubleshooting tips, please update this document following the same structure. Add new endpoints to the reference table, new workflows under Common Workflows, and new issues under Troubleshooting. diff --git a/docs-site/docs/general-practices/prisma-schema-shared-types.md b/docs-site/docs/general-practices/prisma-schema-shared-types.md new file mode 100644 index 0000000000..8a6dc72c9f --- /dev/null +++ b/docs-site/docs/general-practices/prisma-schema-shared-types.md @@ -0,0 +1,622 @@ +--- +title: Prisma Schema and Shared Types +description: Guide for defining Prisma data models and keeping shared TypeScript types in sync in FinishLine. Covers schema conventions, enum patterns, multi-tenant organizationId scoping, the migration workflow, and the shared type barrel export. Use when adding new database models, creating or editing Prisma schema, defining shared types or interfaces, adding enums, running migrations, or when asked how the data layer works. +skill: true +skill_name: prisma-schema-shared-types +--- + +# Prisma Schema and Shared Types + +> **Summary:** How to define data models in Prisma and maintain corresponding TypeScript types in the shared package so backend and frontend stay in sync. + +## Overview + +FinishLine's data layer has two halves that must stay synchronized: the Prisma schema defines the database structure, and the shared TypeScript types define the API contract between backend and frontend. When you add or modify a model, you typically touch both. + +The Prisma schema lives at `src/backend/src/prisma/schema.prisma` — a single file containing all models, enums, and relations. The shared types live in `src/shared/src/types/` as feature-scoped TypeScript files that are re-exported through `src/shared/index.ts`. The backend uses Prisma-generated types internally but transforms them into shared types before sending responses. The frontend imports shared types directly and never references Prisma types. + +This separation exists because Prisma types mirror the database exactly (snake_case joins, nullable FKs, raw DateTime objects), while shared types represent the cleaned-up API contract (camelCase, resolved relations, computed fields). The transformer layer (covered in the `query-args-and-transformers` skill) bridges the gap. + +## Architecture + +``` +┌─────────────────────┐ +│ schema.prisma │ +│ (database truth) │ +└────────┬────────────┘ + │ prisma generate + ▼ +┌─────────────────────┐ +│ @prisma/client │ +│ (generated types) │ +└────────┬────────────┘ + │ used in services + ▼ +┌─────────────────────┐ +│ transformers │ +│ (Prisma → shared) │ +└────────┬────────────┘ + │ returns + ▼ +┌─────────────────────┐ +│ shared/src/types/ │ +│ (API contract) │ +└────────┬────────────┘ + │ imported by + ▼ +┌─────────────────────┐ +│ frontend │ +│ (React app) │ +└─────────────────────┘ +``` + +## File Locations + +- **Prisma schema:** `src/backend/src/prisma/schema.prisma` +- **Migrations:** `src/backend/src/prisma/migrations/` +- **Shared types:** `src/shared/src/types/{feature}-types.ts` +- **Barrel export:** `src/shared/index.ts` +- **Transformers:** `src/backend/src/transformers/{feature}.transformer.ts` +- **Query args:** `src/backend/src/prisma-query-args/{feature}.query-args.ts` + +## Prisma Schema Conventions + +### Model Naming + +Models use `PascalCase` with underscores separating logical words. This matches PostgreSQL conventions and keeps generated Prisma client types readable. + +```prisma +// CORRECT — PascalCase with underscores +model Reimbursement_Request { ... } +model Work_Package { ... } +model Change_Request { ... } +model Event_Type { ... } + +// WRONG — no underscores or camelCase +model ReimbursementRequest { ... } +model workPackage { ... } +``` + +### Field Naming + +Fields use `camelCase`. Foreign key fields end with `Id`. Relation fields use the related model name (camelCase). + +```prisma +model Event { + eventId String @id @default(uuid()) + title String + dateCreated DateTime @default(now()) + dateDeleted DateTime? + userCreatedId String + userCreated User @relation(...) + eventTypeId String + eventType Event_Type @relation(...) +} +``` + +### Primary Keys + +Every model MUST use a UUID string primary key with the pattern `@id @default(uuid())`. The ID field MUST be named `{camelCaseModelName}Id`. + +```prisma +model Vendor { + vendorId String @id @default(uuid()) + // ... +} + +model Reimbursement_Request { + reimbursementRequestId String @id @default(uuid()) + // ... +} +``` + +**Note:** Some older models use a bare `id` field (e.g., `Unit`, `Link_Type`, `Graph`). New models MUST use the `{modelName}Id` convention. + +### Timestamp Fields + +Every new model MUST include a `createdAt` field. An `updatedAt` field is optional and left to the developer's discretion based on whether tracking modification time is useful for the feature: + +```prisma +model My_New_Model { + myNewModelId String @id @default(uuid()) + // ... domain fields ... + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt // optional +} +``` + +**Note:** Most existing models use `dateCreated DateTime @default(now())`. A few newer models (`Part`, `Part_Submission`, `Part_Review`) use `createdAt`/`updatedAt`. New models MUST use `createdAt` (not `dateCreated`) for consistency with the newer convention. + +### Soft Deletion + +Models that support deletion use a nullable `dateDeleted` field and a relation to the deleting user, rather than actually removing rows: + +```prisma +model Example { + exampleId String @id @default(uuid()) + dateDeleted DateTime? + userDeletedId String? + userDeleted User? @relation( + name: "exampleDeleter", + fields: [userDeletedId], + references: [userId] + ) + // ... +} +``` + +Services MUST filter out soft-deleted records by checking `dateDeleted === null` in queries unless specifically retrieving deleted records. + +### Multi-Tenant Organization Scoping + +Every top-level domain model MUST be scoped to an organization, either directly or through a required parent relation. This is FinishLine's multi-tenancy mechanism — all data belongs to exactly one organization. + +**Direct scoping** (most models): + +```prisma +model Vendor { + vendorId String @id @default(uuid()) + name String + // ... other fields ... + organizationId String + organization Organization @relation( + fields: [organizationId], + references: [organizationId] + ) + + @@index([organizationId]) +} +``` + +**Indirect scoping through parent** (child models): + +```prisma +// Project gets organizationId through WBS_Element +model Project { + projectId String @id @default(uuid()) + wbsElementId String @unique + wbsElement WBS_Element @relation( + fields: [wbsElementId], + references: [wbsElementId] + ) + // No organizationId needed — WBS_Element has it +} + +// Work_Package gets it through Project → WBS_Element +model Work_Package { + workPackageId String @id @default(uuid()) + projectId String + project Project @relation( + fields: [projectId], + references: [projectId] + ) +} +``` + +**Rule:** If a model has `organizationId`, it MUST also have `@@index([organizationId])`. + +### Enums + +Enums use `PascalCase` names with `SCREAMING_SNAKE_CASE` values. Enum names use underscores to separate logical words, matching model naming: + +```prisma +enum Event_Status { + UNCONFIRMED + CONFIRMED + SCHEDULED + DONE +} + +enum Reimbursement_Status_Type { + PENDING_LEADERSHIP_APPROVAL + LEADERSHIP_APPROVED + PENDING_FINANCE + PENDING_SABO_SUBMISSION + SABO_SUBMITTED + ADVISOR_APPROVED + REIMBURSED + DENIED +} +``` + +Enums are placed at the top of `schema.prisma`, before model definitions. + +### Relations + +Name all relations explicitly when a model has multiple relations to the same target. Use descriptive `@relation(name: "...")` strings: + +```prisma +model User { + createdEvents Event[] @relation(name: "eventCreator") + deletedEvents Event[] @relation(name: "eventDeleter") +} + +model Event { + userCreatedId String + userCreated User @relation( + name: "eventCreator", + fields: [userCreatedId], + references: [userId] + ) + userDeletedId String? + userDeleted User? @relation( + name: "eventDeleter", + fields: [userDeletedId], + references: [userId] + ) +} +``` + +### Indexes + +Add `@@index` for any foreign key field that will be queried or filtered frequently. At minimum, always index `organizationId` and parent FK fields: + +```prisma +model Receipt { + // ... + reimbursementRequestId String + reimbursementRequest Reimbursement_Request @relation(...) + + @@index([reimbursementRequestId]) +} +``` + +### Unique Constraints + +Use `@@unique` with a `name` parameter for compound unique constraints. Organization-scoped uniqueness is a common pattern: + +```prisma +model Vendor { + // name must be unique within an organization + @@unique([name, organizationId], name: "uniqueVendor") +} + +model Change_Request { + // identifier is unique within an organization + @@unique([identifier, organizationId], + name: "uniqueChangeRequest") +} +``` + +## Shared Type Conventions + +### File Organization + +Each feature domain has its own type file in `src/shared/src/types/`: + +``` +src/shared/src/types/ +├── project-types.ts +├── calendar-types.ts +├── change-request-types.ts +├── reimbursement-requests-types.ts +├── team-types.ts +├── user-types.ts +├── finance-types.ts +├── work-package-types.ts +├── task-types.ts +├── bom-types.ts +├── part-review.types.ts +└── ... +``` + +Every type file MUST be re-exported from the barrel file at `src/shared/index.ts`: + +```typescript +export * from './src/types/calendar-types.js'; +export * from './src/types/project-types.js'; +// ... etc +``` + +**When adding a new type file**, add the corresponding `export *` line to `src/shared/index.ts`. Use the `.js` extension in the import path (ESM convention). + +### Type Naming + +Shared types use `PascalCase` with no underscores — they follow standard TypeScript conventions, not Prisma's: + +| Prisma Model | Shared Type | +| ----------------------- | ---------------------- | +| `Reimbursement_Request` | `ReimbursementRequest` | +| `Work_Package` | `WorkPackage` | +| `Event_Type` | `EventType` | +| `Change_Request` | `ChangeRequest` | + +### Entity Types vs Preview Types + +Many entities have both a full type and a lighter preview type. The full type includes resolved relations; the preview includes only essential fields for list views: + +```typescript +// Full type — used on detail pages +export interface Project extends WbsElement { + summary: string; + budget: number; + workPackages: WorkPackage[]; + teams: TeamPreview[]; + tasks: Task[]; + favoritedBy: User[]; +} + +// Preview type — used in lists and dropdowns +export interface ProjectPreview extends WbsElementPreview { + startDate?: Date; + endDate?: Date; + budget: number; + duration: number; + workPackages: WorkPackagePreview[]; + teams: { teamName: string; teamId: string }[]; +} +``` + +### Enum Mirroring + +Prisma enums MUST have corresponding TypeScript enums in shared types. The TypeScript enum uses `PascalCase` keys mapping to the Prisma `SCREAMING_SNAKE_CASE` values: + +```typescript +// Mirrors prisma enum Event_Status +export enum EventStatus { + UNCONFIRMED = 'UNCONFIRMED', + CONFIRMED = 'CONFIRMED', + SCHEDULED = 'SCHEDULED', + DONE = 'DONE' +} + +// Mirrors prisma enum WBS_Element_Status +export enum WbsElementStatus { + Inactive = 'INACTIVE', + Active = 'ACTIVE', + Complete = 'COMPLETE' +} +``` + +Both patterns exist in the codebase — some use the raw string as the value (`UNCONFIRMED = 'UNCONFIRMED'`), others use readable keys (`Inactive = 'INACTIVE'`). Either is acceptable as long as the values match the Prisma enum exactly. + +### Payload Types for Create and Edit + +Every feature MUST define separate payload types for create and edit operations. These types represent the data the frontend sends to the backend, not the database model structure. + +**Naming convention:** `Create{Feature}Payload` and `Edit{Feature}Payload` (or `{Feature}CreateArgs` for consistency with existing patterns). + +```typescript +// What the frontend sends to create an event +export interface EventTypeCreateArgs { + name: string; + calendarIds: string[]; + requiredMembers: boolean; + optionalMembers: boolean; + teams: boolean; + // ... boolean flags for optional fields +} + +// What the frontend sends to create a reimbursement product +export interface ReimbursementProductCreateArgs { + id?: string; + name: string; + cost: number; + refundSources: CreateRefundSourceArgs[]; +} +``` + +Payload types differ from entity types in important ways: they use IDs instead of resolved objects for relations (e.g., `calendarIds: string[]` not `calendars: Calendar[]`), they omit server-generated fields (`dateCreated`, `organizationId`, `userCreated`), and they may include validation-specific structures. + +**When the codebase doesn't yet have separate create/edit payloads for a feature, add them.** Even if the current code passes raw objects or uses inline types, new and modified code MUST use explicit payload types in the shared package. + +### Type Relationships Across Files + +Shared type files import from each other. Keep imports minimal — prefer importing `Preview` types over full types when the full relation isn't needed: + +```typescript +// In project-types.ts +import { TeamPreview } from './team-types.js'; +import { User, UserPreview } from './user-types.js'; + +export interface Project extends WbsElement { + teams: TeamPreview[]; // NOT Team[] + lead?: User; +} +``` + +## Step-by-Step: Adding a New Model + +### 1. Define the Prisma Model + +Add the model to `src/backend/src/prisma/schema.prisma`: + +```prisma +model Schedule_Slot { + scheduleSlotId String @id @default(uuid()) + startTime DateTime + endTime DateTime + allDay Boolean @default(false) + eventId String + event Event @relation( + fields: [eventId], + references: [eventId] + ) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@index([startTime]) + @@index([endTime]) +} +``` + +### 2. Add Any New Enums + +Place enums at the top of the schema file, before models: + +```prisma +enum Conflict_Status { + PENDING + APPROVED + DENIED + NO_CONFLICT +} +``` + +### 3. Run the Migration + +```bash +yarn prisma:migrate +``` + +This runs `npx prisma migrate dev` from the backend directory. It will prompt you for a migration name — use a descriptive kebab-case name like `add-schedule-slots` or `add-conflict-status-enum`. The migration creates a new SQL file in `src/backend/src/prisma/migrations/`. + +After migrating, Prisma automatically runs `prisma generate` to update the client types. + +**If using Docker for development:** + +```bash +yarn docker:prisma:migrate +``` + +### Manual Migration Steps + +Prisma can auto-generate migrations for simple changes (adding a new model, adding a nullable column, adding an enum value). However, some schema changes require you to **manually edit the generated SQL migration file** because Prisma cannot safely resolve them on its own. Common scenarios: + +- **Adding a required (non-nullable) field to an existing table.** The migration will fail if the table already has rows, because existing rows have no value for the new column. You must either give the column a `@default(...)` in the schema, or manually edit the migration SQL to set a backfill value before adding the `NOT NULL` constraint: + + ```sql + -- Step 1: Add column as nullable + ALTER TABLE "My_Model" ADD COLUMN "newField" TEXT; + -- Step 2: Backfill existing rows + UPDATE "My_Model" SET "newField" = 'default_value'; + -- Step 3: Set NOT NULL constraint + ALTER TABLE "My_Model" + ALTER COLUMN "newField" SET NOT NULL; + ``` + +- **Renaming a column or table.** Prisma interprets renames as a drop + create, which destroys data. You must replace the generated SQL with `ALTER TABLE ... RENAME COLUMN`. + +- **Changing a column's type** (e.g., `Int` → `String`). Prisma may generate a destructive migration. You must manually write a `USING` cast or a multi-step migration. + +- **Splitting or merging models.** Any structural refactor that moves data between tables needs manual SQL to migrate the data. + +**Workflow for manual migrations:** + +1. Run `yarn prisma:migrate` — Prisma generates the migration file +2. **Before applying**, open the generated SQL file in `src/backend/src/prisma/migrations/{timestamp}_{name}/migration.sql` +3. Edit the SQL to handle the data migration safely +4. Run `yarn prisma:migrate` again to apply the edited migration + +Alternatively, use `npx prisma migrate dev --create-only` from `src/backend` to generate the migration file without applying it, edit it, then run `yarn prisma:migrate` to apply. + +### 4. Define the Shared Type + +Create or update the appropriate file in `src/shared/src/types/`: + +```typescript +// In calendar-types.ts + +export enum ConflictStatus { + PENDING = 'PENDING', + APPROVED = 'APPROVED', + DENIED = 'DENIED', + NO_CONFLICT = 'NO_CONFLICT' +} + +export interface ScheduleSlot { + scheduleSlotId: string; + startTime: Date; + endTime: Date; + allDay: boolean; +} + +export interface ScheduleSlotCreateArgs { + startTime: Date; + endTime: Date; + allDay: boolean; +} +``` + +### 5. Export from Barrel + +If you created a new type file, add it to `src/shared/index.ts`: + +```typescript +export * from './src/types/my-new-types.js'; +``` + +### 6. Build Shared Package + +After modifying shared types, rebuild the shared package so the backend and frontend can see the changes: + +```bash +yarn workspace shared build +``` + +Or if using the dev server, it may handle this automatically. + +### 7. Create Transformer and Query Args + +See the `query-args-and-transformers` skill for how to create the Prisma-to-shared-type transformer and the corresponding query args. + +## Key Rules + +- Every Prisma model MUST have a UUID primary key: `{modelName}Id String @id @default(uuid())` +- Every new model MUST include `createdAt DateTime @default(now())`; `updatedAt` is optional +- Every top-level model MUST have `organizationId` directly or inherit it through a required parent relation +- Every `organizationId` field MUST have a corresponding `@@index([organizationId])` +- Soft deletion uses `dateDeleted DateTime?` — NEVER use hard deletes +- Prisma enums MUST have mirrored TypeScript enums in `src/shared/src/types/` +- Shared types MUST be re-exported from `src/shared/index.ts` +- New features MUST define separate `Create` and `Edit` payload types in shared +- Payload types use IDs (`teamIds: string[]`) not resolved objects (`teams: Team[]`) +- Foreign key fields MUST be indexed with `@@index` + +## Common Mistakes + +- **Forgetting to re-export from `src/shared/index.ts`.** The frontend won't see your new types until they're re-exported from the barrel file. If imports fail with "not exported," check the barrel. + +- **Using `id` instead of `{modelName}Id` for the primary key.** Some older models use bare `id`, but new models MUST use the descriptive name. + +- **Missing `organizationId` on a top-level model.** If your model doesn't have a required parent that chains up to an organization, it needs `organizationId` directly. Without it, the service layer can't enforce multi-tenant isolation. + +- **Forgetting `@@index` on foreign keys.** Every FK field that appears in `WHERE` clauses needs an index. At minimum, always index `organizationId` and parent relation FKs. + +- **Prisma enum values not matching shared type values.** The Prisma enum value `PENDING_LEADERSHIP_APPROVAL` must match exactly as the string in the TypeScript enum. A mismatch causes runtime errors when transforming data. + +- **Not running `yarn prisma:migrate` after schema changes.** The database won't reflect your changes until you run the migration. The Prisma client types also won't update until `prisma generate` runs (which `migrate dev` does automatically). + +- **Editing already-applied migration files.** NEVER modify migration files that have already been applied to a database. You CAN and sometimes MUST edit a migration file before it is applied (see "Manual Migration Steps" above). Once applied, create a new migration instead. + +- **Adding a required field without a default or backfill.** If your new column is non-nullable and the table has existing rows, the migration will fail. See "Manual Migration Steps" for how to handle this. + +## Reference Files + +These files demonstrate the conventions well: + +- `src/backend/src/prisma/schema.prisma` — The single source of truth for all models and enums +- `src/shared/src/types/calendar-types.ts` — Good example of entity types, preview types, enums, and create args +- `src/shared/src/types/reimbursement-requests-types.ts` — Good example of complex nested types and multiple payload types +- `src/shared/src/types/project-types.ts` — Good example of type hierarchies (`WbsElement` → `Project`, preview types) +- `src/shared/index.ts` — Barrel export file; every new type file must be added here + +## Checklist + +- [ ] Model name uses `PascalCase` with underscores (e.g., `My_New_Model`) +- [ ] Primary key is `{modelName}Id String @id @default(uuid())` +- [ ] Model has `createdAt DateTime @default(now())` (and optionally `updatedAt DateTime @updatedAt`) +- [ ] Model has `organizationId` (directly or via parent chain) +- [ ] `organizationId` has `@@index([organizationId])` +- [ ] All FK fields have `@@index` declarations +- [ ] Named relations used when multiple relations target the same model +- [ ] Soft deletion uses `dateDeleted DateTime?` pattern (if applicable) +- [ ] Corresponding shared TypeScript types created in `src/shared/src/types/` +- [ ] Shared type file re-exported from `src/shared/index.ts` +- [ ] Prisma enums mirrored as TypeScript enums in shared types +- [ ] Separate `Create` and `Edit` payload types defined for API operations +- [ ] Payload types use IDs for relations, not resolved objects +- [ ] Migration created with `yarn prisma:migrate` +- [ ] Shared package rebuilt with `yarn workspace shared build` + +## Migration Notes + +> This section describes how this pattern differs from older code in the +> codebase. New code MUST follow the patterns above. When modifying existing +> files, update them to match these patterns where practical. + +**Timestamp fields:** Most existing models use `dateCreated DateTime @default(now())`. A few newer models (`Part`, `Part_Submission`, `Part_Review`, `Part_Review_Popup`) use `createdAt`/`updatedAt`. New models MUST use `createdAt` (not `dateCreated`) for the creation timestamp. + +**Primary key naming:** Some older models use a bare `id` field (e.g., `Unit`, `Link_Type`, `Material_Type`, `Manufacturer`, `Graph`, `Graph_Collection`). New models MUST use `{modelName}Id`. + +**Payload types:** The codebase is inconsistent about defining explicit create/edit payload types. Some features have them (e.g., `EventTypeCreateArgs`, `ReimbursementProductCreateArgs`, `ScheduleSlotCreateArgs`), while others pass inline objects or rely on partial Prisma types. The naming also varies between `CreateArgs`, `CreatePayload`, `ApiInputs`, and `FormInput`. New code MUST define explicit payload types. Prefer the `{Feature}CreateArgs` naming to match the majority of existing patterns. diff --git a/docs-site/docs/general-practices/query-args-and-transformers.md b/docs-site/docs/general-practices/query-args-and-transformers.md new file mode 100644 index 0000000000..20f69b43fc --- /dev/null +++ b/docs-site/docs/general-practices/query-args-and-transformers.md @@ -0,0 +1,516 @@ +--- +title: Query Args and Transformers +description: Guide for Prisma query args and transformer functions in FinishLine. Query args define reusable select/include objects for Prisma queries. Transformers convert Prisma results into shared types for the API. Use when creating query args, writing transformers, fetching data from Prisma for API responses, or when asked how data flows from the database to the frontend. +skill: true +skill_name: query-args-and-transformers +--- + +# Query Args and Transformers + +> **Summary:** Query args define what data Prisma fetches from the database. Transformers convert that Prisma data into the shared types sent to the frontend. Together they form the data-shaping layer between Prisma and the API response. + +## Overview + +When a service method needs to return data to the frontend, it goes through two steps: + +1. **Query args** tell Prisma exactly which fields and relations to fetch. They are reusable `select`/`include` objects defined with `Prisma.validator`. +2. **Transformers** take the typed Prisma result and reshape it into a shared type (defined in `src/shared/`) that the frontend expects. + +This separation exists because Prisma's auto-generated types (column names, nested relation shapes, enum values) often differ from the API contract. Transformers handle renaming fields, mapping enums, flattening relations, and filtering out internal data. + +**Critical distinction:** Query args and transformers are ONLY for data being returned to the frontend. For internal queries in a service (validation checks, duplicate detection, permission lookups), use inline `select: {}` clauses directly in the Prisma call. See the "Internal Queries" section below. + +## Architecture + +``` + Service Method + │ + │ uses query args to fetch + ▼ +┌──────────────┐ +│ Prisma │ returns typed result: +│ Query Args │ Prisma.XGetPayload +└──────┬───────┘ + │ + │ passes result to transformer + ▼ +┌──────────────┐ +│ Transformer │ returns shared type +│ │ (API contract) +└──────┬───────┘ + │ + ▼ + Controller sends as JSON +``` + +## File Locations + +| Layer | Path | Naming | +|-------|------|--------| +| Query args | `src/backend/src/prisma-query-args/{feature}.query-args.ts` | `get{Entity}QueryArgs` | +| Transformers | `src/backend/src/transformers/{feature}.transformer.ts` | `{entity}Transformer` | +| Shared types | `src/shared/src/types/{feature}-types.ts` | TypeScript interfaces | + +## Query Args + +### Structure + +Every query args file follows the same pattern: export a type alias using `ReturnType`, and export a function that returns a `Prisma.validator` call. + +```typescript +// src/backend/src/prisma-query-args/shop.query-args.ts +import { Prisma } from '@prisma/client'; +import { getUserQueryArgs } from './user.query-args.js'; + +export type ShopQueryArgs = + ReturnType; + +export const getShopQueryArgs = ( + organizationId: string +) => + Prisma.validator()({ + include: { + userCreated: getUserQueryArgs(organizationId) + } + }); +``` + +The type alias (`ShopQueryArgs`) is used by the transformer to type its input parameter via `Prisma.ShopGetPayload`. This creates end-to-end type safety: if you change what the query fetches, the transformer's input type updates automatically and TypeScript will flag any mismatches. + +### `select` vs `include` + +**Always prefer `select` over `include`.** `include` fetches all columns on the relation plus the specified nested relations. `select` fetches only the fields you list. + +```typescript +// GOOD — fetches only what's needed +teams: { + select: { + teamName: true, + teamId: true + } +} + +// AVOID — fetches every column on Team +teams: true + +// ALSO AVOID — include fetches all Team +// columns plus the nested relation +teams: { + include: { + teamType: true + } +} +``` + +Use `include` only when the transformer genuinely needs all (or nearly all) columns from the relation AND also needs nested relations. The `getWorkPackageQueryArgs` function uses `include` on `wbsElement` because the transformer needs most of its fields plus several nested relations. But even within that, nested relations like `teams` use `select` when only a few fields are needed. + +A good example of selective fetching is `getWorkPackagePreviewQueryArgs`, which uses `select` at every level to fetch the minimal data for a dropdown/list view: + +```typescript +export const getWorkPackagePreviewQueryArgs = () => + Prisma.validator< + Prisma.Work_PackageDefaultArgs + >()({ + select: { + blockedBy: true, + wbsElement: { + select: { + wbsElementId: true, + carNumber: true, + projectNumber: true, + workPackageNumber: true, + dateCreated: true, + dateDeleted: true, + name: true, + lead: getUserPreviewQueryArgs(), + manager: getUserPreviewQueryArgs(), + status: true + } + }, + project: { + select: { + projectId: true, + wbsElement: { + select: { + name: true, + links: getLinkQueryArgs() + } + } + } + }, + startDate: true, + duration: true, + workPackageId: true, + stage: true + } + }); +``` + +### Nesting + +Be very careful about nested query args. Every level of nesting adds database joins and increases query cost. Only include nested relations when the transformer actually needs that data to satisfy the shared type. + +**Good reasons to nest:** +- The shared type has a `userCreated: User` field → nest `getUserQueryArgs` +- The shared type has a `teams: Team[]` field that needs team names → nest with `select: { teamName: true, teamId: true }` + +**Bad reasons to nest:** +- "The frontend might need it eventually" — add it when it's actually needed +- Nesting three or more levels deep without confirming the transformer uses all that data + +When nesting gets deep, consider whether a separate endpoint with its own query args would be better. For example, `getEventQueryArgs` and `getEventWithMembersQueryArgs` exist as two separate functions because the member-expanded version adds significant nesting that most callers don't need. + +### `organizationId` Parameter + +Many query args accept `organizationId` to scope nested relations. The most common case is filtering user roles to the current organization: + +```typescript +export const getUserQueryArgs = ( + organizationId?: string +) => + Prisma.validator()({ + select: { + roles: organizationId + ? { where: { organizationId } } + : true, + userId: true, + firstName: true, + lastName: true, + email: true + } + }); +``` + +Pass `organizationId` through from the service method. If your query args don't need to filter nested relations by org, the parameter can be omitted. + +### Filtering Soft-Deleted Records + +Query args MUST filter out soft-deleted records in nested relations using `where: { dateDeleted: null }`. This applies at every nesting level: + +```typescript +export const getWorkPackageQueryArgs = ( + organizationId: string +) => + Prisma.validator< + Prisma.Work_PackageDefaultArgs + >()({ + include: { + blockedBy: { + where: { dateDeleted: null } + }, + events: { + where: { dateDeleted: null }, + ...getEventQueryArgs(organizationId) + }, + wbsElement: { + include: { + descriptionBullets: { + where: { dateDeleted: null }, + ...getDescriptionBulletQueryArgs( + organizationId + ) + }, + changes: { + where: { + changeRequest: { dateDeleted: null } + } + }, + blocking: { + where: { + wbsElement: { dateDeleted: null } + } + } + } + } + } + }); +``` + +Note: the top-level `dateDeleted: null` filter is applied in the service's `where` clause, not in the query args. Query args handle nested relation filtering. + +### Circular Dependencies + +The `user.query-args.ts` file has a comment: `// DO NOT CALL ANY OTHER QUERY ARGS FROM HERE TO AVOID CIRCULAR DEPENDENCIES`. Because user query args are nested into almost every other query args file, they sit at the bottom of the dependency tree. If user query args imported from, say, `event.query-args.ts`, it would create a circular import. Keep this in mind when adding new nesting. + +## Transformers + +### Structure + +A transformer is a pure function that takes a Prisma result (typed using the query args) and returns a shared type. + +```typescript +// src/backend/src/transformers/calendar.transformer.ts +import { Prisma } from '@prisma/client'; +import { Shop } from 'shared'; +import { ShopQueryArgs } + from '../prisma-query-args/shop.query-args.js'; +import { userTransformer } + from './user.transformer.js'; + +export const shopTransformer = ( + shop: Prisma.ShopGetPayload +): Shop => { + return { + shopId: shop.shopId, + name: shop.name, + description: shop.description, + dateCreated: shop.dateCreated, + userCreated: userTransformer(shop.userCreated) + }; +}; +``` + +**The input type** is always `Prisma.{Model}GetPayload<{QueryArgs}>`. This gives you a type that exactly matches what Prisma returns when using those query args. + +**The return type** is always the shared type from `src/shared/`. The transformer's job is to bridge any gap between the two. + +### Common Transformer Operations + +**Renaming fields** — when Prisma column names differ from the shared type: +```typescript +color: calendar.colorHexCode, +``` + +**Mapping enums** — Prisma enums and shared enums are separate types. Create a mapping: +```typescript +export const eventStatusTransformer = ( + status: PrismaEventStatus +): EventStatus => { + const mapping: Record< + PrismaEventStatus, EventStatus + > = { + UNCONFIRMED: EventStatus.UNCONFIRMED, + CONFIRMED: EventStatus.CONFIRMED, + SCHEDULED: EventStatus.SCHEDULED, + DONE: EventStatus.DONE + }; + return mapping[status]; +}; +``` + +**Converting nulls to undefined** — Prisma uses `null` for optional fields, but shared types often use `undefined`: +```typescript +location: event.location ?? undefined, +zoomLink: event.zoomLink ?? undefined, +``` + +**Transforming nested relations** — call other transformers for nested objects: +```typescript +requiredMembers: + event.requiredMembers.map(userTransformer), +teams: event.teams.map((team) => ({ + ...team, + members: team.members.map(userTransformer), + leads: team.leads.map(userTransformer), + head: userTransformer(team.head) +})), +``` + + +**Computing derived fields** — some shared types have fields that don't exist in the database: +```typescript +endDate: calculateEndDate( + wpInput.startDate, wpInput.duration +), +deleted: wpInput.wbsElement.dateDeleted !== null, +``` + +### Composing Transformers + +Transformers compose naturally. A `shopMachineryTransformer` calls `shopTransformer`, which calls `userTransformer`: + +```typescript +export const shopMachineryTransformer = ( + sm: Prisma.Shop_MachineryGetPayload< + ShopMachineryQueryArgs + > +): ShopMachinery => { + return { + shopMachineryId: sm.shopMachineryId, + shop: shopTransformer(sm.shop), + quantity: sm.quantity + }; +}; +``` + +This mirrors the nesting in query args: `getMachineryQueryArgs` includes `getShopMachineryQueryArgs`, which includes `getShopQueryArgs`. The transformer chain matches the query args chain. + +### Preview Transformers + +When the frontend needs a lightweight version of an entity (for dropdowns, lists, or cards), create a separate "preview" query args and transformer pair: + +```typescript +// Query args: minimal select +export const getWorkPackagePreviewQueryArgs = () => + Prisma.validator< + Prisma.Work_PackageDefaultArgs + >()({ + select: { /* only essential fields */ } + }); + +// Transformer: maps to preview type +export const workPackagePreviewTransformer = ( + wp: Prisma.Work_PackageGetPayload< + WorkPackagePreviewQueryArgs + > +): WorkPackagePreview => { + return { /* minimal fields */ }; +}; +``` + +This avoids fetching heavyweight data (nested changes, description bullets, events) when all the frontend needs is a name and ID. + +## Internal Queries (Not for API Response) + +When a service method queries the database for validation, permission checks, duplicate detection, or calculations — NOT to return data to the frontend — do NOT use query args. Write inline `select` clauses: + +```typescript +// Checking for duplicates: only need the ID +const duplicate = await prisma.shop.findFirst({ + where: { + organizationId: organization.organizationId, + dateDeleted: null, + name: { equals: name, mode: 'insensitive' } + }, + select: { shopId: true } +}); + +// Counting members: only need the count +const team = await prisma.team.findUnique({ + where: { teamId }, + select: { + _count: { select: { members: true } } + } +}); + +// Checking existence and org ownership +const calendar = await prisma.calendar.findUnique({ + where: { calendarId }, + select: { + calendarId: true, + organizationId: true, + dateDeleted: true + } +}); +``` + +The principle is simple: query args exist to satisfy shared types via transformers. Everything else should fetch the minimum data needed. + +## How It All Connects in a Service + +Here's the full flow in a service method: + +```typescript +static async getSingleShop( + shopId: string, + organization: Organization +): Promise { + // 1. Fetch with query args (for API response) + const shop = await prisma.shop.findUnique({ + where: { shopId }, + ...getShopQueryArgs(organization.organizationId) + }); + + // 2. Validate existence + if (!shop) throw new NotFoundException( + 'Shop', shopId + ); + if (shop.dateDeleted) + throw new DeletedException('Shop', shopId); + if ( + shop.organizationId !== + organization.organizationId + ) + throw new InvalidOrganizationException('Shop'); + + // 3. Transform and return + return shopTransformer(shop); +} +``` + +For mutations that need both internal lookups and a final return: + +```typescript +static async editShop( + submitter: User, + shopId: string, + name: string, + description: string, + organization: Organization +): Promise { + // Internal lookup — inline select + const existing = await prisma.shop.findUnique({ + where: { shopId }, + select: { + shopId: true, + organizationId: true, + dateDeleted: true + } + }); + + if (!existing) throw new NotFoundException( + 'Shop', shopId + ); + // ... more validation ... + + // Write + fetch for response — query args + const updated = await prisma.shop.update({ + where: { shopId }, + data: { name, description }, + ...getShopQueryArgs(organization.organizationId) + }); + + return shopTransformer(updated); +} +``` + +## Key Rules + +- Query args are ONLY for data returned to the frontend via transformers. Use inline `select` for internal queries. +- Always prefer `select` over `include` to avoid over-fetching. +- Only add nested query args when the transformer actually needs that data for the shared type. +- Export a type alias using `ReturnType` for every query args function. +- Transformer input MUST be typed as `Prisma.{Model}GetPayload<{QueryArgs}>`. +- Transformer return type MUST be a shared type from `src/shared/`. +- NEVER return raw Prisma objects from a service. Always transform. +- Filter `dateDeleted: null` in nested relations within query args. +- Convert Prisma `null` to `undefined` when the shared type uses optional fields. +- Map Prisma enums to shared enums explicitly — do not assume they are the same type. +- Do not import other query args from `user.query-args.ts` to avoid circular dependencies. + +## Common Mistakes + +- **Using query args for internal lookups.** Fetching full nested relations just to check if a record exists wastes database resources. Use `select: { id: true }`. +- **Using `include: true`** on a relation when only a few fields are needed. Switch to `select` with specific fields. +- **Adding deep nesting "just in case."** Every nested level adds joins. Only nest what the transformer uses. +- **Forgetting `dateDeleted: null`** in nested `where` clauses within query args. This returns soft-deleted child records. +- **Returning Prisma objects directly** without a transformer. Even if the shapes look identical today, they can diverge when the schema or shared types change. +- **Forgetting `?? undefined`** on nullable Prisma fields that map to optional shared type fields. TypeScript will catch this, but it's easy to miss. +- **Not creating a preview variant** when a lightweight version exists. If the frontend has both a detail view and a list view, make separate query args and transformers for each. + +## Reference Files + +- `src/backend/src/prisma-query-args/work-packages.query-args.ts` — Shows both a full query args (with `include`) and a preview query args (with `select` throughout) +- `src/backend/src/prisma-query-args/event.query-args.ts` — Two variants (`getEventQueryArgs` and `getEventWithMembersQueryArgs`) for different data needs +- `src/backend/src/prisma-query-args/user.query-args.ts` — Base-level query args with `select`-first approach, org-scoped role filtering, and circular dependency warning +- `src/backend/src/transformers/calendar.transformer.ts` — Comprehensive transformer file showing enum mapping, null-to-undefined conversion, nested transformers, and soft-delete filtering +- `src/backend/src/transformers/work-packages.transformer.ts` — Demonstrates computed fields (`endDate`, `deleted`) and full/preview transformer pair + +## Checklist + +When adding query args and a transformer for a new entity: + +- [ ] Query args function uses `Prisma.validator()` +- [ ] Type alias exported as `ReturnType` +- [ ] `organizationId` parameter included if nested relations need org scoping +- [ ] `select` preferred over `include` at every level +- [ ] Nested relations filtered with `where: { dateDeleted: null }` where applicable +- [ ] No unnecessary deep nesting +- [ ] No circular dependency on `user.query-args.ts` +- [ ] Transformer input typed as `Prisma.{Model}GetPayload<{QueryArgs}>` +- [ ] Transformer return type is the shared type from `src/shared/` +- [ ] All nullable Prisma fields converted with `?? undefined` if shared type uses optional +- [ ] Prisma enums mapped to shared enums explicitly +- [ ] Nested relations transformed using their respective transformer functions +- [ ] Soft-deleted nested records filtered if not handled in query args +- [ ] Preview variant created if a lightweight view is needed diff --git a/docs-site/docs/general-practices/react-components.md b/docs-site/docs/general-practices/react-components.md new file mode 100644 index 0000000000..66805457d8 --- /dev/null +++ b/docs-site/docs/general-practices/react-components.md @@ -0,0 +1,548 @@ +--- +title: React Components +description: Guide for building and organizing React components in FinishLine. Covers shared vs page-specific component decisions, prop interface design, MUI sx styling, styled() MUI extensions, stateless component patterns, and the container/view split. Use when creating new React components, refactoring UI code, deciding where a component belongs, or when asked about component architecture or styling conventions. +skill: true +skill_name: react-components +--- + +# React Component Architecture + +> **Summary:** FinishLine organizes React components into a shared library (`src/frontend/src/components/`) and page-specific directories (`src/frontend/src/pages/{Feature}/`). Shared components are stateless, prop-driven building blocks. Page components compose them into features, own state, and handle data fetching. + +## Overview + +FinishLine's frontend is built from two layers of components. The **shared component library** contains reusable, stateless UI primitives — buttons, form fields, modals, display blocks, layout shells, and data presentation widgets. These components know nothing about business logic; they receive data through props and notify parents through callbacks. + +**Page-level components** live in feature directories under `src/frontend/src/pages/`. They compose shared components into complete features, own local state (edit mode, modal visibility, active tab), fetch data via React Query hooks, and handle user interactions. Complex pages often use a **container/view split** where a container component manages data fetching and state while a view component handles pure rendering. + +Before building any new component, always check `src/frontend/src/components/` first. The shared library already covers common patterns — detail displays, modals, form fields, buttons, search bars, loading states, progress bars, tabs, and more. Duplicating existing functionality is a common mistake for new developers. + +## Architecture + +``` +src/frontend/src/ +├── components/ ← Shared library +│ ├── NERButton.tsx (styled MUI) +│ ├── NERFormModal.tsx (form wrapper) +│ ├── NERAutocomplete.tsx (controlled input) +│ ├── DetailDisplay.tsx (label + value) +│ ├── PageLayout.tsx (page shell) +│ ├── LoadingIndicator.tsx (loading state) +│ ├── SearchBar.tsx (search input) +│ ├── Toast/ (multi-file) +│ │ ├── Toast.tsx +│ │ └── ToastProvider.tsx +│ └── ... +└── pages/ ← Feature pages + └── ProjectDetailPage/ + ├── ProjectPage.tsx (entry) + ├── DeleteProject.tsx (container) + ├── DeleteProjectView.tsx (view) + ├── ProjectForm/ (edit mode) + └── ProjectViewContainer/ (read mode) + ├── ProjectViewContainer.tsx + ├── ProjectDetails.tsx + ├── WorkPackageSummary.tsx + └── ... +``` + +**Data flow in a typical page:** + +``` +┌──────────┐ React Query ┌───────────┐ +│ Page │──────────────▶│ Container │ +│ (entry) │ hook data │ (state) │ +└──────────┘ └─────┬─────┘ + │ props + ┌─────▼─────┐ + │ View │ + │ (render) │ + └─────┬─────┘ + │ composes + ┌────────────┼────────────┐ + ▼ ▼ ▼ + PageLayout DetailDisplay NERButton + (shared) (shared) (shared) +``` + +## Component Categories + +FinishLine has three distinct component categories. Each has different rules. + +### 1. Shared Functional Components + +Standard React functional components in `src/frontend/src/components/`. These are the most common type. They accept a typed props interface, render MUI components, and return JSX. + +**Examples:** `DetailDisplay`, `NERAutocomplete`, `PageLayout`, `SearchBar`, `InfoBlock`, `NERFormModal`, `ActionsMenu`, `LoadingIndicator` + +### 2. Styled MUI Extensions + +Components created with MUI's `styled()` utility that extend a base MUI component with FinishLine-specific theming. These are thin wrappers — often under 30 lines — that set colors, sizes, and hover states to match the FinishLine design system (red: `#ef4345`). + +**Examples:** `NERButton`, `NERSuccessButton`, `NERFailButton`, `NERSwitch`, `NERProgressBar` + +### 3. Page-Specific Components + +Components that live in a page's directory and are only used by that feature. These include entry-point page components, container/view pairs, and feature-specific sub-components like `WorkPackageSummary` or `ProjectDetails`. + +**Examples:** `ProjectPage`, `DeleteProject` / `DeleteProjectView`, `ProjectViewContainer`, `ProjectDetails` + +## File Locations and Naming + +**Shared components:** `src/frontend/src/components/{ComponentName}.tsx` + +- Single-file components: `NERAutocomplete.tsx`, `DetailDisplay.tsx` +- Multi-file components (rare): `Toast/Toast.tsx`, `Toast/ToastProvider.tsx`, `Link/LinkView.tsx` +- Use a subdirectory only when the component has multiple closely related files + +**Page components:** `src/frontend/src/pages/{FeaturePage}/{ComponentName}.tsx` + +- Entry point: `{Feature}Page.tsx` (e.g., `ProjectPage.tsx`) +- Containers: `{Action}{Feature}.tsx` (e.g., `DeleteProject.tsx`) +- Views: `{Action}{Feature}View.tsx` (e.g., `DeleteProjectView.tsx`) +- Sub-components: descriptive name (e.g., `ProjectDetails.tsx`, `WorkPackageSummary.tsx`) +- Subdirectories for complex tab content (e.g., `ProjectViewContainer/`, `ProjectForm/`) + +**Naming conventions:** + +- PascalCase for all component files and component names +- File name MUST match the default export name +- Prefix shared components with `NER` when they wrap/extend MUI components (e.g., `NERButton`, `NERFormModal`, `NERAutocomplete`) +- Do NOT prefix page-specific components with `NER` + +## Prop Design Conventions + +### TypeScript Interfaces (Required) + +Every component that accepts props MUST define a named TypeScript interface. Never use inline type annotations on the function parameter. + +```tsx +// ✅ CORRECT — named interface +interface DetailDisplayProps { + label: string; + content: string; + paddingRight?: number; + copyButton?: boolean; +} + +const DetailDisplay: React.FC = ({ + label, content, paddingRight = 0, copyButton = false +}) => { ... }; + +// ❌ WRONG — inline type +const DetailDisplay: React.FC<{ + label: string; content: string; +}> = ({ label, content }) => { ... }; + +// ❌ WRONG — no type at all +const DetailDisplay = ({ label, content }) => { ... }; +``` + +**Interface naming:** `{ComponentName}Props` — always. For exported prop types that other files need, export the interface from the component file. + +### Required vs Optional Props + +- Props that the component cannot render without are **required** (no `?`) +- Style overrides, feature flags, and callbacks with sensible defaults are **optional** (`?`) with default values in destructuring +- Use `= defaultValue` in the parameter destructuring, not `defaultProps` + +```tsx +interface SearchBarProps { + searchText: string; // required + setSearchText: (text: string) => void; // required + placeholder?: string; // optional +} + +export const SearchBar = ({ + searchText, + setSearchText, + placeholder = 'Search...' +}: SearchBarProps) => { ... }; +``` + +### Style Override with `sx` + +Shared components that render MUI elements MUST accept an optional `sx` prop to allow callers to apply style overrides: + +```tsx +interface NERAutocompleteProps { + id: string; + options: { label: string; id: string }[]; + onChange: (event: React.SyntheticEvent, value: { ... } | null) => void; + sx?: SxProps; // ← always optional + // ... +} +``` + +The component spreads or merges `sx` into its root element's styles: + +```tsx +const autocompleteStyle = { + backgroundColor: theme.palette.background.default, + width: '100%', + ...sx // caller overrides win +}; +``` + +### Callback Props + +Components that respond to user interactions MUST expose callbacks as props rather than performing side effects internally. Name callbacks descriptively: + +- `onChange`, `onClick`, `onSubmit` — for standard DOM-like events +- `onHide`, `onClose` — for dismissal actions +- `setSearchText`, `setTab` — for controlled state (matching the `useState` setter convention) +- `enterEditMode`, `handleClose` — for domain-specific actions + +### Children + +Components that act as layout wrappers (e.g., `PageLayout`, `InfoBlock`, `NERFormModal`) accept `children: ReactNode`. Use `React.FC` which includes `children` implicitly, or declare it explicitly in the interface. + +### Extending MUI Props + +When wrapping an MUI component, extend its prop type to preserve pass-through capabilities: + +```tsx +interface NERButtonProps extends ButtonProps { + whiteVariant?: boolean; +} +``` + +## Styling Rules + +### MUI `sx` Prop (Preferred) + +All styling MUST use MUI's `sx` prop. The `sx` prop supports theme-aware values, responsive breakpoints, and pseudo-selectors. + +```tsx +// ✅ CORRECT — sx prop + + {label} + + + +``` + +### `styled()` for Reusable Theme Extensions + +Use MUI's `styled()` utility when creating a reusable component that permanently overrides an MUI component's default styling. This is appropriate for design-system primitives, not one-off styling. + +```tsx +import { Button, styled } from '@mui/material'; + +const NERSuccessButton = styled(Button)(({ theme }) => ({ + backgroundColor: theme.palette.success.main, + color: theme.palette.success.contrastText, + '&:hover': { + backgroundColor: theme.palette.success.dark + } +})) as typeof Button; + +export default NERSuccessButton; +``` + +Use `styled()` when: + +- The component is a permanent design-system token (brand buttons, switches, progress bars) +- The styles are static and theme-derived, not dynamic from props +- Multiple consumers will use the same styled version + +### What to Avoid + +- **NEVER use inline `style={{}}`** — use `sx` instead. Legacy components with `style` should be migrated to `sx` when touched. +- **NEVER use CSS modules for new components** — `LoadingIndicator` uses CSS modules as a legacy pattern. New components MUST use `sx` or `styled()`. +- **NEVER use CSS-in-JS libraries** (styled-components, emotion's `css` prop directly) — use MUI's built-in `sx` and `styled()` APIs only. + +### FinishLine Brand Colors + +When referencing brand colors in `styled()` components, use `#ef4345` (FinishLine red). In functional components, prefer theme palette values: + +```tsx +// In styled() components — direct hex is acceptable +backgroundColor: '#ef4345'; + +// In functional components — prefer theme +const theme = useTheme(); +theme.palette.primary.main; +theme.palette.error.main; +theme.palette.success.main; +``` + +## Statelessness and State Management + +### Shared Components: Stateless by Default + +Shared components MUST prefer statelessness. They receive data via props and notify parents via callbacks. They do NOT: + +- Fetch data (no React Query hooks) +- Manage form state (receive `control` from parent via React Hook Form) +- Track UI state that belongs to the parent (modal open/close, edit mode) + +```tsx +// ✅ CORRECT — stateless, parent controls everything +interface SearchBarProps { + searchText: string; + setSearchText: (text: string) => void; + placeholder?: string; +} + +export const SearchBar = ({ searchText, setSearchText, placeholder = 'Search...' }: SearchBarProps) => { + return ( + + setSearchText(e.target.value)} /> + + ); +}; +``` + +The only state allowed in shared components is **transient UI state** that is purely internal to the component's rendering (e.g., `anchorEl` for a dropdown menu position in `ActionsMenu`). + +### Page Components: Own Their State + +Page-level components are where state lives. They use `useState` for UI state, React Query hooks for server data, and React Hook Form for form state: + +```tsx +const ProjectPage: React.FC = ({ wbsNum }) => { + const [editMode, setEditMode] = useState(false); + const { isLoading, isError, data, error } = useSingleProject(wbsNum); + + if (isError) return ; + if (isLoading || !data) return ; + + if (editMode) { + return setEditMode(false)} />; + } + return setEditMode(true)} />; +}; +``` + +### The `useEffect` Rule + +`useEffect` MUST NOT be used unless it is for one of these cases: + +1. **External subscriptions** — WebSocket connections, event listeners on `window`/`document` +2. **Timers** — `setTimeout`, `setInterval`, `requestAnimationFrame` +3. **Non-React library integration** — initializing a chart library, D3 bindings, imperative DOM APIs + +Do NOT use `useEffect` for: + +- Deriving state from props (use computed values or `useMemo`) +- Syncing React state with other React state (restructure state instead) +- Responding to prop changes (use event handlers or key-based remounting) + +> **Legacy note:** Some existing components (e.g., `FullPageTabs`) use `useEffect` to sync with browser navigation state. This is acceptable in legacy code but MUST NOT be replicated in new components. New components should use router hooks or event handlers directly. + +## The Container/View Pattern + +For components with complex interactions (forms, delete confirmations, multi-step workflows), split into a **container** that manages logic and a **view** that handles rendering. + +### Container + +- Handles data fetching and mutation hooks +- Manages loading/error states +- Calls toast notifications on success/error +- Passes data and callbacks down as props + +```tsx +// DeleteProject.tsx (container) +interface DeleteProjectProps { + modalShow: boolean; + handleClose: () => void; + wbsNum: WbsNumber; +} + +const DeleteProject: React.FC = ({ modalShow, handleClose, wbsNum }) => { + const toast = useToast(); + const { isLoading, isError, error, mutateAsync } = useDeleteProject(); + + const handleConfirm = async ({ wbsNum }: DeleteProjectInputs) => { + try { + await mutateAsync(validateWBS(wbsNum)); + handleClose(); + toast.success(`Project #${wbsPipe(wbsNum)} Deleted!`); + } catch (e) { + if (e instanceof Error) toast.error(e.message); + } + }; + + if (isLoading) return ; + if (isError) return ; + + return ; +}; +``` + +### View + +- Pure rendering only — no hooks other than `useForm` +- Receives all data and callbacks via props +- Owns form setup (schema, `useForm`, validation) when it is a form view + +```tsx +// DeleteProjectView.tsx (view) +interface DeleteProjectViewProps { + project: WbsNumber; + modalShow: boolean; + onHide: () => void; + onSubmit: (data: DeleteProjectInputs) => Promise; +} + +const DeleteProjectView: React.FC = ({ + project, modalShow, onHide, onSubmit +}) => { + const { handleSubmit, control, reset, formState } = useForm({ + resolver: yupResolver(schema), + defaultValues: { wbsNum: '' }, + mode: 'onChange' + }); + + return ( + + {/* form content */} + + ); +}; +``` + +### When to Use Container/View + +Use the container/view split when a component does **both** data fetching/mutation **and** has non-trivial rendering logic. Simple components that just display fetched data (like `ProjectDetails`) can combine both in one file — the split is for managing complexity, not a rigid rule. + +## When to Create a Shared Component + +A component belongs in `src/frontend/src/components/` when: + +1. **Two or more pages need it** — if you find yourself copying a component between page directories, extract it to shared +2. **It is a general UI pattern** — detail displays, modals, buttons, form fields, status pills, search inputs, loading states +3. **It has no domain-specific business logic** — shared components know about visual presentation, not Work Packages or Change Requests + +A component stays in its page directory when: + +1. **Only one feature uses it** — `WorkPackageSummary` is only relevant to the project detail page +2. **It contains feature-specific business logic** — `BOMTab` composes shared components but encodes BOM-specific display rules +3. **It is a container** — containers with data-fetching hooks and mutation logic are always page-specific + +**When in doubt:** Start page-specific. Extract to shared when a second consumer appears. Premature extraction creates unused abstractions. + +## Step-by-Step: Creating a New Shared Component + +1. **Check the existing library.** Search `src/frontend/src/components/` for similar functionality. If something close exists, extend it with new props rather than creating a duplicate. + +2. **Define the props interface.** Name it `{ComponentName}Props`. Include `sx?: SxProps` if the component renders MUI elements. Make props that have sensible defaults optional. + +3. **Write a stateless functional component.** Use `React.FC` typing. Destructure props with defaults. Do not add state unless absolutely necessary for transient UI behavior. + +4. **Style with `sx`.** Use the `sx` prop on MUI components. Use `useTheme()` for theme-aware values. Merge caller's `sx` override into the root element. + +5. **Export as default.** One component per file, default export, file name matches component name. + +```tsx +import { Box, Typography, SxProps, Theme, useTheme } from '@mui/material'; + +interface StatusBadgeProps { + label: string; + color: 'success' | 'error' | 'warning'; + sx?: SxProps; +} + +const StatusBadge: React.FC = ({ label, color, sx }) => { + const theme = useTheme(); + + return ( + + {label} + + ); +}; + +export default StatusBadge; +``` + +## Key Rules + +- Every component that accepts props MUST define a named `{ComponentName}Props` interface — NEVER use inline types +- Shared components MUST be stateless — receive data via props, notify parents via callbacks +- NEVER use `useEffect` unless it is for an external subscription, timer, or non-React library integration +- ALWAYS use MUI `sx` prop for styling — NEVER use inline `style={{}}` +- ALWAYS check `src/frontend/src/components/` before building a new component +- Shared components MUST NOT contain data-fetching hooks (React Query) or mutation logic +- ALWAYS accept `sx?: SxProps` on shared components that render MUI elements +- One component per file, default export, file name matches component name +- Prefix shared MUI wrapper components with `NER` (e.g., `NERButton`, `NERModal`) + +## Common Mistakes + +- **Building a component that already exists.** The shared library has 50+ components. Search before creating. Common ones missed: `DetailDisplay` (label-value pairs), `InfoBlock` (titled sections), `NERFormModal` (form dialogs), `ActionsMenu` (dropdown action buttons). + +- **Using `useEffect` to derive state.** If you need to compute something from props, use a local variable or `useMemo`. If you need to "reset" state when a prop changes, use a `key` prop on the component instead. + +- **Using inline `style` instead of `sx`.** MUI's `sx` supports theme values, responsive breakpoints, and pseudo-selectors. Inline `style` does not. + +- **Putting data-fetching in a shared component.** Shared components render data — they don't fetch it. If your shared component needs a React Query hook, it should be a page component instead, or the data should be passed as a prop. + +- **Defining props inline.** Always create a named interface. This makes props discoverable, exportable, and consistent across the codebase. + +- **Creating a shared component too early.** Start page-specific. Extract when a second page needs the same component. Unused shared components are clutter. + +## Reference Files + +**Shared components (good examples of prop design and statelessness):** + +- `src/frontend/src/components/NERAutocomplete.tsx` — Controlled input with full props interface, `sx` override, form error integration +- `src/frontend/src/components/DetailDisplay.tsx` — Minimal stateless display component with optional features +- `src/frontend/src/components/PageLayout.tsx` — Layout shell with children, optional header elements, breadcrumbs +- `src/frontend/src/components/SearchBar.tsx` — Controlled search with `styled()` sub-components and callback pattern +- `src/frontend/src/components/ActionsMenu.tsx` — Shared component with allowable transient UI state (menu anchor) + +**Styled MUI extensions:** + +- `src/frontend/src/components/NERSuccessButton.tsx` — Clean `styled()` theme extension +- `src/frontend/src/components/NERSwitch.tsx` — Complex `styled()` with pseudo-selectors + +**Page components (good examples of composition and container/view):** + +- `src/frontend/src/pages/ProjectDetailPage/ProjectPage.tsx` — Entry point with loading/error handling and edit mode toggle +- `src/frontend/src/pages/ProjectDetailPage/DeleteProject.tsx` — Container with mutation logic and toast handling +- `src/frontend/src/pages/ProjectDetailPage/DeleteProjectView.tsx` — Pure form view with `NERFormModal` and React Hook Form +- `src/frontend/src/pages/ProjectDetailPage/ProjectViewContainer/ProjectViewContainer.tsx` — Complex page composing many shared components + +## Checklist + +- [ ] Searched `src/frontend/src/components/` for existing components before creating new ones +- [ ] Props interface is named `{ComponentName}Props` (not inline) +- [ ] Component is `React.FC` with default export matching file name +- [ ] Shared component is stateless (no data fetching, no `useEffect`, no owned UI state beyond transient menu anchors) +- [ ] Styling uses `sx` prop, not inline `style` +- [ ] Shared components that render MUI elements accept optional `sx?: SxProps` +- [ ] Callbacks are exposed as props, not handled internally +- [ ] `styled()` is only used for permanent design-system tokens, not one-off styling +- [ ] Page components handle loading/error states with `LoadingIndicator` and `ErrorPage` +- [ ] Complex interactions use the container/view split + +## Migration Notes + +> This section describes how this pattern differs from older code in the +> codebase. New code MUST follow the patterns above. When modifying existing +> files, update them to match these patterns where practical. + +**Inline `style` → `sx`:** Some older components (e.g., `WarningBanner`) use `style={{}}` instead of MUI's `sx` prop. When touching these files, migrate to `sx`. + +**CSS Modules → `sx`/`styled()`:** `LoadingIndicator` uses a CSS module (`loading-indicator.module.css`). New components MUST NOT use CSS modules. When significantly refactoring components that use CSS modules, migrate to `sx` or `styled()`. + +**`useEffect` for router sync:** `FullPageTabs` uses `useEffect` to sync tab state with the browser URL. This is acceptable as legacy code but MUST NOT be replicated. New components should use router hooks or event handlers directly. diff --git a/docs-site/docs/general-practices/repository-overview.md b/docs-site/docs/general-practices/repository-overview.md new file mode 100644 index 0000000000..424f4f0845 --- /dev/null +++ b/docs-site/docs/general-practices/repository-overview.md @@ -0,0 +1,343 @@ +--- +title: Repository Overview +description: High-level overview of the FinishLine monorepo structure, tech stack, tools, and how they work together. Use when onboarding to the codebase, asking about the project structure, wondering what technology FinishLine uses, asking where files live, or needing to understand how the frontend, backend, and shared packages relate to each other. +skill: true +skill_name: repository-overview +--- + +# Repository Overview + +> **Summary:** FinishLine is a TypeScript monorepo with a React frontend, Express backend, and shared type package, managed with Yarn workspaces and built for Northeastern Electric Racing's project management needs. + +## What is FinishLine? + +FinishLine is a full-stack ERP and project management application built for **Northeastern Electric Racing (NER)**, a student engineering organization at Northeastern University that designs, builds, and races electric vehicles. The platform manages work breakdown structures, change requests, reimbursements, bill of materials, user onboarding, calendar events, supply chain operations, team management, and more. + +The primary users are engineering students, team leads, and club advisors. NER is structured into subteams (mechanical, electrical, software, business, etc.) with roles including guests, members, leadership, heads, admins, and app admins. FinishLine supports multi-tenant organizations — all data is scoped by `organizationId`. + +## Monorepo Structure + +FinishLine uses **Yarn workspaces** to manage three packages in a single repository: + +``` +src/ +├── backend/ # Express API server (Node.js) +├── frontend/ # React SPA (Vite) +└── shared/ # Common TypeScript types and utilities +``` + +The root `package.json` declares these workspaces and provides top-level scripts that orchestrate builds, tests, and development servers. The `shared` package MUST be built before the frontend or backend can use it, because they import its compiled output. + +### Backend (`src/backend/`) + +The backend is an **Express 5** server using **Prisma ORM** with **PostgreSQL**. It follows a layered architecture: + +``` +src/backend/ +├── index.ts # App entry: middleware, route registration, error handler +├── src/ +│ ├── routes/ # Express route definitions with express-validator +│ ├── controllers/ # Thin request handlers — extract data, call service, return response +│ ├── services/ # Business logic — static class methods, filter by organizationId +│ ├── prisma/ # Schema, migrations, seed data, Prisma client singleton +│ ├── prisma-query-args/# Reusable Prisma select/include argument objects +│ ├── transformers/ # Convert Prisma models to API response shapes (shared types) +│ ├── integrations/ # External service clients (Slack) +│ └── utils/ # Auth middleware, custom exceptions, validation, helpers +└── tests/ + ├── unit/ # Service-level unit tests (vitest) + ├── integration/ # Integration tests + ├── test-data/ # Test fixtures + └── test-utils.ts # Shared test helpers +``` + +Key technology choices: +- **Express 5** for HTTP routing and middleware +- **Prisma 6** as the ORM with PostgreSQL +- **express-validator** for request input validation on routes +- **express-jwt** and **jsonwebtoken** for JWT-based authentication +- **Vitest** for unit and integration testing +- **Multer** for file uploads +- **Slack Web API** for Slack integration +- **Google APIs** for Google Calendar/Drive integration + +### Frontend (`src/frontend/`) + +The frontend is a **React 19** single-page application built with **Vite**: + +``` +src/frontend/ +├── src/ +│ ├── index.tsx # ReactDOM entry point +│ ├── app/ # Context providers, routing, auth wrappers +│ ├── pages/ # Route-level page components (one directory per feature) +│ ├── components/ # Reusable UI components (NERFormModal, NERDataGrid, etc.) +│ ├── hooks/ # React Query hooks wrapping API calls +│ ├── apis/ # Axios API call functions with response transformers +│ │ └── transformers/ # Frontend-specific response transformers +│ ├── layouts/ # Layout components +│ ├── utils/ # Routes, URL builders, pipes, types, axios config +│ ├── stylesheets/ # SCSS stylesheets +│ └── tests/ # Component, hook, and page tests (vitest) +``` + +Key technology choices: +- **React 19** with functional components and hooks +- **Vite 6** for dev server and production builds +- **Material-UI (MUI) v6** for the component library and styling +- **React Query v3** (`react-query` 3.17.0) for server state management +- **React Hook Form v7** with **Yup** validation for forms +- **React Router DOM v5** for client-side routing +- **Axios** for HTTP requests to the backend +- **Recharts** and **Chart.js** for data visualization +- **date-fns** and **dayjs** for date manipulation +- **Vitest** for testing with React Testing Library + +### Shared (`src/shared/`) + +The shared package contains **TypeScript type definitions** and **utility functions** used by both the frontend and backend: + +``` +src/shared/ +├── index.ts # Re-exports everything +└── src/ + ├── types/ # TypeScript interfaces for API contracts + │ ├── project-types.ts + │ ├── user-types.ts + │ ├── calendar-types.ts + │ ├── change-request-types.ts + │ ├── finance-types.ts + │ ├── reimbursement-requests-types.ts + │ ├── work-package-types.ts + │ ├── team-types.ts + │ ├── bom-types.ts + │ ├── statistics-types.ts + │ ├── part-review.types.ts + │ └── ... + ├── backend-supports/ # Backend-specific shared logic + ├── date-utils.ts # Shared date utilities + ├── permission-utils.ts # Role/permission checking + ├── validate-wbs.ts # WBS number validation + ├── utils.ts # General utilities + └── word-count.ts # Word count utility +``` + +Types are imported throughout the codebase as: +```typescript +import { Project, User, WbsNumber } from 'shared'; +``` + +The shared package compiles to `dist/` via TypeScript and is referenced by the other packages through Yarn workspace resolution. + +## How the Pieces Work Together + +### End-to-End Data Flow + +A typical request flows through the system like this: + +``` +Page Component + │ + ▼ +Hook (useQuery / useMutation) + │ + ▼ +API function (Axios) + │ + ── HTTP request ──▶ Route (validation) + │ + ▼ + Controller + │ + ▼ + Service (business logic) + │ + ▼ + Prisma (DB + transaction) + │ + ▼ + Transformer (Prisma → shared type) + │ + ◀── HTTP response ─── + │ + ▼ +Frontend transformer → shared type + │ + ▼ +Hook returns data to component +``` + +Shared types define the API contract at every boundary. + +1. A **React page component** renders UI and calls a **hook** (`useQuery` for reads, `useMutation` for writes). +2. The hook calls an **API function** in `src/frontend/src/apis/` which uses **Axios** to make an HTTP request. For reads, the API function applies a **frontend transformer** to convert the raw response into the shared type. +3. The request hits an **Express route** which runs **express-validator** middleware for input validation, then calls the **controller**. +4. The **controller** is a thin layer: it extracts data from the request (`req.body`, `req.params`, `req.currentUser`, `req.organization`), calls the **service** method, and returns the result with an HTTP status code. +5. The **service** contains the business logic. It validates permissions, enforces business rules, queries the database via **Prisma**, and returns data. For responses, it uses a **backend transformer** to convert Prisma models into the shared API types. +6. **Shared types** (`src/shared/src/types/`) define the data shapes at every boundary. The backend transformer produces these types; the frontend API function expects them. + +### Authentication and Multi-Tenancy + +Every request (except login and health check) passes through middleware defined in `src/backend/index.ts`: + +1. **JWT validation** (`requireJwtProd` or `requireJwtDev`) — verifies the user's identity and stores `userId` in `res.locals`. +2. **`getUserAndOrganization`** — looks up the user and organization from the database, verifies the user belongs to the organization, and attaches both to `req.currentUser` and `req.organization`. + +This means every controller and service method has access to the authenticated user and their organization. Services MUST filter all database queries by `organizationId` to enforce data isolation. + +On the frontend, the Axios interceptor in `src/frontend/src/utils/axios.ts` automatically attaches the `organizationId` header and the authorization token to every request. + +### Context Providers + +The frontend wraps the app in a provider hierarchy (see `src/frontend/src/app/AppMain.tsx` → `AppContext.tsx`): + +``` +ClarityProvider → Analytics (Microsoft Clarity) + AppContext → Composed provider wrapper + QueryClientProvider → React Query cache + OrganizationContext → Current organization state + AuthContext → Current user authentication + ThemeContext → MUI theme (light/dark) + HomePageProvider → Home page state + ToastProvider → Toast notifications + BrowserRouter → React Router v5 + OAuthProvider → Google OAuth +``` + +### HTTP Method Convention + +FinishLine uses an unconventional HTTP method pattern: **GET for reads, POST for everything else** (creates, updates, and deletes). The backend does not use PUT, PATCH, or DELETE methods. + +## Key File Location Reference + +When looking for code related to a specific feature, files follow a consistent naming pattern across the stack: + +| Layer | Path Pattern | Example (Calendar) | +|-------|-------------|-------------------| +| Routes | `src/backend/src/routes/{feature}.routes.ts` | `calendar.routes.ts` | +| Controllers | `src/backend/src/controllers/{feature}.controllers.ts` | `calendar.controllers.ts` | +| Services | `src/backend/src/services/{feature}.services.ts` | `calendar.services.ts` | +| Prisma Query Args | `src/backend/src/prisma-query-args/{feature}.query-args.ts` | `calendar.query-args.ts` | +| Transformers | `src/backend/src/transformers/{feature}.transformer.ts` | `calendar.transformer.ts` | +| Backend Utils | `src/backend/src/utils/{feature}.utils.ts` | `calendar.utils.ts` | +| Backend Tests | `src/backend/tests/unit/{feature}.test.ts` | `calendar.test.ts` | +| Shared Types | `src/shared/src/types/{feature}-types.ts` | `calendar-types.ts` | +| Frontend APIs | `src/frontend/src/apis/{feature}.api.ts` | `calendar.api.ts` | +| Frontend Hooks | `src/frontend/src/hooks/{feature}.hooks.ts` | `calendar.hooks.ts` | +| Frontend Pages | `src/frontend/src/pages/{FeaturePage}/` | `CalendarPage/` | +| Frontend Utils | `src/frontend/src/utils/{feature}.utils.ts` | `calendar.utils.ts` | +| Frontend Tests | `src/frontend/src/tests/pages/{FeaturePage}/` | — | +| URL Builders | `src/frontend/src/utils/urls.ts` | (all in one file) | +| Frontend Routes | `src/frontend/src/utils/routes.ts` | (all in one file) | + +## Feature Areas + +FinishLine covers the following major feature areas. Each has its own slice through the full stack (routes, services, hooks, pages, types): + +- **Work Breakdown Structure (WBS):** Projects and Work Packages with status tracking, description bullets, and stage gates +- **Change Requests:** Formal approval workflow for scope, timeline, and budget changes (multiple CR types: standard, activation, stage gate, budget) +- **Finance:** Reimbursement requests with multi-step approval chains, vendors, sponsors, sponsor tiers, account codes, index codes +- **Calendar:** Events, event types, calendars, shops, machinery, schedule slots, and a confirmation/scheduling workflow +- **Teams & Users:** Role-based access control, team assignments, team types, user settings, secure settings, schedule settings +- **Onboarding:** Checklists with ordered items for new member onboarding +- **Parts & BOM:** Part creation, part review workflow (submissions, review requests, reviews), bill of materials (materials, assemblies, manufacturers, units) +- **Statistics:** Custom graphs, graph collections, and dashboard analytics +- **Retrospective:** Timelines and budget retrospectives for completed work +- **Recruitment:** Milestones and FAQs for the recruitment pipeline +- **Notifications & Announcements:** Push notifications, pop-ups, and announcements +- **Tasks:** Task tracking tied to WBS elements with status and priority +- **Gantt:** Timeline visualization for projects and work packages +- **Organizations:** Multi-tenant organization settings, useful links, featured projects, images, contacts + +## Development Environment + +### Prerequisites + +FinishLine requires **Docker** for the PostgreSQL database regardless of how you run the application code. You MUST have Docker installed and running before starting development. + +### Initial Setup + +First time setup (or after pulling new dependencies): +```bash +yarn install # Install all workspace dependencies +yarn prisma:generate # Generate the Prisma client from the schema +``` + +### Database Setup + +The PostgreSQL database always runs in a Docker container. The `yarn database:setup` command handles everything: it writes the `DATABASE_URL` to `src/backend/.env`, starts a PostgreSQL container named `finishline` on port 5432, creates the `nerpm` database, and runs Prisma migrations with seed data: +```bash +yarn database:setup # One-time: create Postgres container + seed DB +``` + +After initial setup, the container persists. If you restart your machine, start it again with `docker start finishline`. + +### Running the Application + +You have two options for running the frontend and backend: on your host machine or in Docker containers. Either way, they connect to the same PostgreSQL container. + +**Option A: Host machine (recommended for faster iteration)** +```bash +yarn start # Builds shared, starts backend (nodemon, port 3001) + # + frontend (vite, port 3000) concurrently +``` + +Or run them individually: +```bash +yarn frontend # Frontend dev server on port 3000 +yarn backend:dev # Backend with nodemon on port 3001 +yarn workspace shared build # Rebuild shared (required after changing shared types) +``` + +**Option B: Docker containers** +```bash +yarn docker:start # Start frontend + backend + DB containers +yarn docker:dev # Full docker dev environment with watch mode +yarn docker:i # Install deps inside containers +``` + +### Database Commands + +These commands manage the Prisma schema and database state: +```bash +yarn prisma:generate # Regenerate Prisma client — run after ANY schema.prisma change +yarn prisma:migrate # Create and apply a new migration — run after adding/changing + # models, fields, enums, or relations in schema.prisma +yarn prisma:reset # Drop the database, re-run all migrations, and re-seed — useful + # when your local DB is in a bad state or you want a clean slate +yarn prisma:studio # Open Prisma Studio GUI — a visual database browser for debugging +``` + +### Testing + +Tests run against a **separate** PostgreSQL container on port 5433 so they don't interfere with your development database. You MUST run the setup script before testing and the teardown script after: + +```bash +yarn test:setup # Spins up a test Postgres container (port 5433) + # and adds a test DATABASE_URL to .env + +yarn test # Run all tests (backend then frontend) +yarn test:backend # Backend unit tests only (vitest) +yarn test:frontend # Frontend tests only (vitest) + +yarn test:teardown # Stops and removes the test container, + # removes the test DATABASE_URL from .env +``` + +The setup script appends a second `DATABASE_URL` pointing at port 5433 to `src/backend/.env`. Prisma uses the last `DATABASE_URL` in the file, so tests hit the test database while the line is present. The teardown script removes it, restoring the original dev database URL. If you skip teardown, your dev server will point at the (stopped) test database and fail to connect. + +### Code Quality + +```bash +yarn lint # ESLint +yarn prettier-check # Prettier formatting check +yarn tsc-check # TypeScript type checking (frontend + backend) +``` + +## ESLint Rules + +The project enforces strict ESLint rules including: `guard-for-in`, `prefer-arrow-callback`, `eqeqeq` (strict equality), `no-var`, `prefer-const`, `prefer-destructuring`, `object-shorthand`, `no-else-return`, `no-lonely-if`, `no-throw-literal`, and `prefer-spread`. See the root `package.json` `eslintConfig` section for the full configuration. + +## License + +FinishLine is licensed under **GNU AGPLv3**. Source files include a license header comment. diff --git a/docs-site/docs/intro.md b/docs-site/docs/intro.md new file mode 100644 index 0000000000..4aa5c8c705 --- /dev/null +++ b/docs-site/docs/intro.md @@ -0,0 +1,45 @@ +--- +title: Introduction +description: Welcome to the FinishLine developer documentation +skill: false +--- + +# FinishLine Developer Documentation + +Welcome to the FinishLine developer documentation! This site contains comprehensive guides for developing and maintaining the FinishLine project management platform. + +## What is FinishLine? + +FinishLine is a full-stack ERP and project management application built for **Northeastern Electric Racing (NER)**, a student engineering organization at Northeastern University that designs, builds, and races electric vehicles. + +## Documentation Structure + +The documentation is organized by topic in the sidebar. Browse the categories to find guides on: + +- Setting up your development environment +- Backend architecture and patterns +- API development and testing +- Database queries and data transformations +- And more! + +## Getting Started + +If you're new to the project, we recommend starting with: + +1. [Repository Overview](general-practices/repository-overview) - Understand the overall architecture and set up your development environment +2. [Backend Endpoints](general-practices/backend-endpoints) - Learn the backend patterns and API structure +3. [Postman API Testing](general-practices/postman-api-testing) - Learn how to test APIs with Postman + +## Contributing + +This documentation is the source of truth for developer guides. To contribute: + +1. Edit the relevant documentation file in `docs-site/docs/` +2. Run `yarn docs:dev` to see your changes +3. If you edited a skill doc (`skill: true`), run `yarn skills:sync` to update Claude's skills +4. Submit a pull request with your documentation changes + +## Need Help? + +- Check the [GitHub repository](https://github.com/Northeastern-Electric-Racing/FinishLine) +- Reach out to the development team on Slack diff --git a/docs-site/docusaurus.config.js b/docs-site/docusaurus.config.js new file mode 100644 index 0000000000..5e4a9cd5f8 --- /dev/null +++ b/docs-site/docusaurus.config.js @@ -0,0 +1,97 @@ +// @ts-check +// `@type` JSDoc annotations allow editor autocompletion and type checking +// (when paired with `@ts-check`). +// There are various equivalent ways to declare your Docusaurus config. +// See: https://docusaurus.io/docs/api/docusaurus-config + +import {themes as prismThemes} from 'prism-react-renderer'; + +/** @type {import('@docusaurus/types').Config} */ +const config = { + title: 'FinishLine Documentation', + tagline: 'Developer documentation for Northeastern Electric Racing\'s project management platform', + favicon: 'img/favicon.ico', + + // Production URL - update this when deploying + url: 'https://northeastern-electric-racing.github.io', + // Base URL - update if deploying to a subdirectory (e.g., /FinishLine/) + baseUrl: '/', + + // GitHub pages deployment config. + // If you aren't using GitHub pages, you don't need these. + organizationName: 'Northeastern-Electric-Racing', // Usually your GitHub org/user name. + projectName: 'FinishLine', // Usually your repo name. + + onBrokenLinks: 'throw', + + // Markdown configuration + markdown: { + format: 'mdx', + mermaid: false, + hooks: { + onBrokenMarkdownLinks: 'warn', + }, + }, + + // Even if you don't use internationalization, you can use this field to set + // useful metadata like html lang. For example, if your site is Chinese, you + // may want to replace "en" with "zh-Hans". + i18n: { + defaultLocale: 'en', + locales: ['en'], + }, + + presets: [ + [ + 'classic', + /** @type {import('@docusaurus/preset-classic').Options} */ + ({ + docs: { + sidebarPath: './sidebars.js', + // Point to the source documentation files in docs-site/docs/ + editUrl: + 'https://github.com/Northeastern-Electric-Racing/FinishLine/edit/main/docs-site/docs/', + }, + blog: false, + theme: { + customCss: './src/css/custom.css', + }, + }), + ], + ], + + themeConfig: + /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ + ({ + // Social card for link previews (uses logo for now) + image: 'img/logo.png', + navbar: { + title: 'FinishLine Docs', + logo: { + alt: 'NER Logo', + src: 'img/logo.png', + href: '/docs/intro', + }, + items: [ + { + type: 'docSidebar', + sidebarId: 'tutorialSidebar', + position: 'left', + label: 'Documentation', + }, + { + href: 'https://github.com/Northeastern-Electric-Racing/FinishLine', + label: 'GitHub', + position: 'right', + }, + ], + }, + + prism: { + theme: prismThemes.github, + darkTheme: prismThemes.dracula, + }, + }), +}; + +export default config; diff --git a/docs-site/package.json b/docs-site/package.json new file mode 100644 index 0000000000..3192c0b650 --- /dev/null +++ b/docs-site/package.json @@ -0,0 +1,48 @@ +{ + "name": "finishline-docs", + "version": "1.0.0", + "private": true, + "scripts": { + "docusaurus": "docusaurus", + "start": "docusaurus start --port 3002", + "build": "docusaurus build", + "swizzle": "docusaurus swizzle", + "deploy": "docusaurus deploy", + "clear": "docusaurus clear", + "serve": "docusaurus serve", + "write-translations": "docusaurus write-translations", + "write-heading-ids": "docusaurus write-heading-ids", + "sync-skills": "node scripts/sync-skills.js", + "generate-sidebar": "node scripts/generate-sidebar.js", + "docs:dev": "yarn generate-sidebar && yarn start", + "docs:build": "yarn generate-sidebar && yarn build" + }, + "dependencies": { + "@docusaurus/core": "^3.1.0", + "@docusaurus/preset-classic": "^3.1.0", + "@mdx-js/react": "^3.0.0", + "clsx": "^2.0.0", + "prism-react-renderer": "^2.3.0", + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "devDependencies": { + "@docusaurus/module-type-aliases": "^3.1.0", + "@docusaurus/types": "^3.1.0" + }, + "browserslist": { + "production": [ + ">0.5%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 3 chrome version", + "last 3 firefox version", + "last 5 safari version" + ] + }, + "engines": { + "node": ">=18.0" + } +} diff --git a/docs-site/scripts/generate-sidebar.js b/docs-site/scripts/generate-sidebar.js new file mode 100644 index 0000000000..d67fc5fee5 --- /dev/null +++ b/docs-site/scripts/generate-sidebar.js @@ -0,0 +1,104 @@ +const fs = require('fs'); +const path = require('path'); + +// Paths +const DOCS_DIR = path.join(__dirname, '../docs'); +const SIDEBAR_PATH = path.join(__dirname, '../sidebars.js'); + +/** + * Recursively build sidebar structure from docs directory + */ +function buildSidebarStructure(dir, basePath = '') { + const items = []; + const entries = fs.readdirSync(dir, { withFileTypes: true }); + + // Separate files and directories + const files = entries.filter((e) => e.isFile() && e.name.endsWith('.md') && e.name !== 'intro.md'); + const directories = entries.filter((e) => e.isDirectory()); + + // Sort alphabetically + files.sort((a, b) => a.name.localeCompare(b.name)); + directories.sort((a, b) => a.name.localeCompare(b.name)); + + // Process directories (categories) + directories.forEach((dirEntry) => { + const dirPath = path.join(dir, dirEntry.name); + const categoryItems = buildSidebarStructure(dirPath, path.join(basePath, dirEntry.name)); + + if (categoryItems.length > 0) { + // Convert directory name to human-readable label + const label = dirEntry.name + .split('-') + .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) + .join(' '); + + items.push({ + type: 'category', + label: label, + items: categoryItems, + }); + } + }); + + // Process files in current directory + files.forEach((file) => { + const docId = path.join(basePath, file.name.replace('.md', '')).replace(/\\/g, '/'); + items.push(docId); + }); + + return items; +} + +/** + * Generate sidebars.js file + */ +function generateSidebars() { + try { + console.log('🔄 Generating sidebar...\n'); + + if (!fs.existsSync(DOCS_DIR)) { + console.error(`❌ Error: Docs directory not found at ${DOCS_DIR}`); + process.exit(1); + } + + const sidebarItems = buildSidebarStructure(DOCS_DIR); + + const sidebarsContent = `/** + * Auto-generated sidebar configuration. + * + * This file is automatically generated from the docs/ folder structure. + * To regenerate: yarn generate-sidebar + * + * To modify the sidebar: + * - Rename folders/files to change labels + * - Reorder by renaming (alphabetical order is used) + * - Create nested folders for hierarchical categories + */ + +// @ts-check + +/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ +const sidebars = { + tutorialSidebar: [ + { + type: 'doc', + id: 'intro', + label: 'Introduction', + }, +${sidebarItems.map((item) => ' ' + JSON.stringify(item, null, 2).split('\n').join('\n ')).join(',\n')}, + ], +}; + +export default sidebars; +`; + + fs.writeFileSync(SIDEBAR_PATH, sidebarsContent); + console.log('✓ Generated sidebars.js\n'); + } catch (error) { + console.error('\n❌ Error generating sidebar:'); + console.error(error.message); + process.exit(1); + } +} + +generateSidebars(); diff --git a/docs-site/scripts/sync-skills.js b/docs-site/scripts/sync-skills.js new file mode 100644 index 0000000000..301315e46a --- /dev/null +++ b/docs-site/scripts/sync-skills.js @@ -0,0 +1,224 @@ +const fs = require('fs'); +const path = require('path'); + +// Paths +const DOCS_DIR = path.join(__dirname, '../docs'); +const SKILLS_DIR = path.join(__dirname, '../../.claude/skills'); + +/** + * Recursively find all markdown files + */ +function findMarkdownFiles(dir, fileList = []) { + const files = fs.readdirSync(dir); + + files.forEach((file) => { + const filePath = path.join(dir, file); + const stat = fs.statSync(filePath); + + if (stat.isDirectory()) { + findMarkdownFiles(filePath, fileList); + } else if (file.endsWith('.md')) { + fileList.push(filePath); + } + }); + + return fileList; +} + +/** + * Parse frontmatter from markdown + */ +function parseFrontmatter(content) { + // Handle both Unix (\n) and Windows (\r\n) line endings + const frontmatterRegex = /^---\r?\n([\s\S]*?)\r?\n---/; + const match = content.match(frontmatterRegex); + + if (!match) { + return { metadata: {}, content }; + } + + const yamlContent = match[1]; + const restOfContent = content.slice(match[0].length); + + // Parse YAML + const lines = yamlContent.split('\n'); + const metadata = {}; + let currentKey = null; + let currentValue = ''; + + lines.forEach((line) => { + const keyMatch = line.match(/^(\w+):\s*(.*)$/); + if (keyMatch) { + // Save previous key-value pair + if (currentKey) { + let value = currentValue.trim(); + // Handle booleans + if (value === 'true') value = true; + else if (value === 'false') value = false; + // Remove quotes + else if (typeof value === 'string') { + value = value.replace(/^["']|["']$/g, ''); + } + metadata[currentKey] = value; + } + // Start new key + currentKey = keyMatch[1]; + currentValue = keyMatch[2]; + } else if (currentKey && line.trim()) { + // Continue multi-line value + currentValue += ' ' + line.trim(); + } + }); + + // Save last key-value pair + if (currentKey) { + let value = currentValue.trim(); + if (value === 'true') value = true; + else if (value === 'false') value = false; + else if (typeof value === 'string') { + value = value.replace(/^["']|["']$/g, ''); + } + metadata[currentKey] = value; + } + + return { metadata, content: restOfContent }; +} + +/** + * Transform to Claude SKILL.md format + */ +function transformToSkillFormat(metadata, content) { + const skillFrontmatter = `--- +name: ${metadata.skill_name} +description: >- + ${metadata.description} +---`; + + return skillFrontmatter + content; +} + +/** + * Transform Docusaurus links to SKILL.md links + * Handles: ./doc or ../category/doc → proper SKILL.md paths + * Avoids double-adding /SKILL.md if it's already there + */ +function transformLinksForSkills(content) { + // Match markdown links and transform them + content = content.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (fullMatch, linkText, linkPath) => { + // Skip if already ends with /SKILL.md + if (linkPath.endsWith('/SKILL.md')) { + return fullMatch; + } + + // Skip external links (http/https) + if (linkPath.startsWith('http://') || linkPath.startsWith('https://')) { + return fullMatch; + } + + // Skip anchor links + if (linkPath.startsWith('#')) { + return fullMatch; + } + + // Transform ./doc → ../doc/SKILL.md + if (linkPath.startsWith('./')) { + const cleanPath = linkPath.substring(2); // Remove ./ + return `[${linkText}](../${cleanPath}/SKILL.md)`; + } + + // Transform ../doc → ../../doc/SKILL.md + if (linkPath.startsWith('../')) { + return `[${linkText}](../${linkPath}/SKILL.md)`; + } + + // Leave other links unchanged + return fullMatch; + }); + + return content; +} + +/** + * Process a single doc file + */ +function processDocFile(docPath) { + const content = fs.readFileSync(docPath, 'utf-8'); + const { metadata, content: bodyContent } = parseFrontmatter(content); + + // Skip if not flagged as a skill + if (!metadata.skill) { + return null; + } + + // Validate required fields + if (!metadata.skill_name) { + console.warn(`⚠️ ${path.basename(docPath)} has skill:true but no skill_name, skipping`); + return null; + } + + // Transform content + const transformedContent = transformToSkillFormat(metadata, bodyContent); + const linkedContent = transformLinksForSkills(transformedContent); + + // Determine skill path (recreate folder/file/SKILL.md structure) + const relativePath = path.relative(DOCS_DIR, path.dirname(docPath)); + const skillDir = path.join(SKILLS_DIR, relativePath, metadata.skill_name); + const skillPath = path.join(skillDir, 'SKILL.md'); + + // Create directory and write + fs.mkdirSync(skillDir, { recursive: true }); + fs.writeFileSync(skillPath, linkedContent); + + const relativeSkillPath = path.relative(SKILLS_DIR, skillPath); + console.log(`✓ Synced: ${path.basename(docPath)} → ${relativeSkillPath}`); + + return skillPath; +} + +/** + * Main function + */ +function main() { + try { + console.log('🔄 Syncing documentation to skills...\n'); + + // Check if docs exists + if (!fs.existsSync(DOCS_DIR)) { + console.error(`❌ Error: Docs directory not found at ${DOCS_DIR}`); + console.error('Create documentation in docs-site/docs/ first'); + process.exit(1); + } + + // Clean skills directory + if (fs.existsSync(SKILLS_DIR)) { + fs.rmSync(SKILLS_DIR, { recursive: true }); + console.log('✓ Cleaned skills directory'); + } + + // Create skills directory + fs.mkdirSync(SKILLS_DIR, { recursive: true }); + + // Find all docs + const docFiles = findMarkdownFiles(DOCS_DIR); + console.log(`Found ${docFiles.length} documentation files\n`); + + // Process each file + let syncedCount = 0; + docFiles.forEach((docPath) => { + const result = processDocFile(docPath); + if (result) syncedCount++; + }); + + if (syncedCount === 0) { + console.warn('\n⚠️ No skills generated! Make sure your docs have skill:true in frontmatter'); + } else { + console.log(`\n✅ Sync complete! ${syncedCount} skills generated\n`); + } + } catch (error) { + console.error('\n❌ Error syncing documentation:'); + console.error(error.message); + process.exit(1); + } +} + +main(); diff --git a/docs-site/src/css/custom.css b/docs-site/src/css/custom.css new file mode 100644 index 0000000000..b6ccea4897 --- /dev/null +++ b/docs-site/src/css/custom.css @@ -0,0 +1,30 @@ +/** + * Any CSS included here will be global. The classic template + * bundles Infima by default. Infima is a CSS framework designed to + * work well for content-centric websites. + */ + +/* You can override the default Infima variables here. */ +:root { + --ifm-color-primary: #ef4345; + --ifm-color-primary-dark: #ec2022; + --ifm-color-primary-darker: #e61113; + --ifm-color-primary-darkest: #be0e10; + --ifm-color-primary-light: #f26668; + --ifm-color-primary-lighter: #f37577; + --ifm-color-primary-lightest: #f79c9d; + --ifm-code-font-size: 95%; + --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); +} + +/* For readability concerns, you should choose a lighter palette in dark mode. */ +[data-theme='dark'] { + --ifm-color-primary: #f26668; + --ifm-color-primary-dark: #f04446; + --ifm-color-primary-darker: #ef3537; + --ifm-color-primary-darkest: #d91e20; + --ifm-color-primary-light: #f4888a; + --ifm-color-primary-lighter: #f59799; + --ifm-color-primary-lightest: #f8b7b8; + --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); +} diff --git a/docs-site/src/pages/index.js b/docs-site/src/pages/index.js new file mode 100644 index 0000000000..1f6f29f007 --- /dev/null +++ b/docs-site/src/pages/index.js @@ -0,0 +1,6 @@ +import React from 'react'; +import { Redirect } from '@docusaurus/router'; + +export default function Home() { + return ; +} diff --git a/docs-site/static/img/favicon.ico b/docs-site/static/img/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..f2f3cabc84db7c1066afd5c88c38dcd445b88a59 GIT binary patch literal 261950 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 U?J9*PmP*blik_%}&Y^+-2b40#<^TWy literal 0 HcmV?d00001 diff --git a/docs-site/static/img/logo.png b/docs-site/static/img/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..77b5d37c91b3b255c4a8b5254e74f68f1f60500b GIT binary patch literal 487234 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
tMuc zr9nn2N8NPB#^nX7v<*(`XYWl~;_u>UD!%-kq@E*#uJV@`a7|V5nlf)KpkF(xEF$3X zT*!JjOwoC|pwxEX&6Exk&m_pPH`x($7?F3kT!l4mrgwu0x6<$msV5y62*ze;`D}|H zK9T%Bp_u;N#lbJV7472B&JOfc|Den{ROmLf^kW;y!1#dnnEKDt)oFfk-Atr_$uzKk zoagMC58UtORcdL|IFq)M*r1~*3_{w;eaSX2Rd{8B3-!JfVzs2cwh8^3{DNb>bm*Dm zTb$$EK>ADPi!uG-(KKMWFby{C2F%8iK=()Cm}3rT)_wVTkn_;;Vm0LVJW*WbEWnea z4=k`vWIcQclDg5;l_Vej>)O7E{guhmJ4W*qOj(>>b8IL?4r9eAE%$LEwvVZElrgRG zqPNekpRHUG_bv(au}|3VN}nRhGXa`SKD8xs zgD&IOHBIaCuU0HmPix5vfo*O)M#Al@Q%i2*(oSA*n#=u_U-4T+fo7YzN7}7UVMt9j zZhRc4E>BJTV>h;I2U4?TNK)iDi6iv&936j$ljq0-SS3S)Tp#v=EN}LzK6F>8{YENZ z<@CJf=UZ86sGdsvQ>p29pfe)fZWiBpDqN6`gapBZe=Eti+8fV&2gQT=JbtQ-XS*K! z+G1aDOe}z-8UXSlm{tFCkaE^M+-`hT+>^FVWBHOQSRK= zeDXyhHo$t>NbL#hg=Wx$7l+;j_9J)9104S!OsHN57s$BsBd3e+#nP40%dxpP-Gb-& z$1|z#7M5!M-^$i1wL9@AJyRYUrL`NX&-0niQ*6Z|kzap9j`yg_moM7R1`A0UHfl^X z!gmWc8E^7tu9dM5R-?h?D{0mA-}|-5Rb@=oR*aJtv|d&BNb6?g6)Q zHl7cgvZ@xYr=vCuAI4RtDQWx?_bgm2P!Y6?lY-Vy12g2ifV-%&&yk&d04q)ZU;4=EXhjVB=OHLF|KR! zG`7vjapGh0ykj_e1l9rmVoIw>!6oZwaQ_}Z#OLXC zAXN=$JOTWTw=cBE&gBbV+H&(g(4}1-vC((!87}k(rL0q(!4c7=4Ilk>^YTnk) ziMnZdn`qJaguZD<+)XZhxgDXxoMhulFF)b|X^+bcpLyxby_U%wt%t~7D}&2+Zd%z8 zZ?(ndUrp>c28Nw)tb+a&_TA~EKf2tEo(vy2@)Zy0)M|~?9+lB@_@6p9CMPG%duNWS z3dsHq8?K12D4Fzw&LBeHX=1c@N$;fcYI~ZXk2p*c8cUE*>f=y|<vgS<# zqSrDK98>@#Q&8&Bp@&o>^`*^7$}jE|u38u;Z`ZjrvJAj~0@&+7hZA_uY;BomWOO{k z3F1xi5UZS{HZJPb0d?E!^+QilEZtp&e{)Ne!9zrCxn??qV{J1}r%n6i6bw|8ws~+> zn>H?2>d~5FFo#o8`Szz`p4@?(x+ZgExH_c4+rbh*Hm|J{h<{0+*O8=5{4>#{e}Y~T z^Sy-$@o>y&Navv+o#P@^dr-nYMn2nd7Swu_;G+Ne>RKZ33u#XW-dmtSZ)i6Es3BO3 z$a0zROT@rumv@wnd}@q6S^quKW>uKG`FIY6CQ$3i!_O%UA20IzRZD4Sc~*}yjjo}} z#z;#adPbr%j^WGKO>4Ghp042ax3&vAl-eD07YaoGE%yRWNn;x|bBJCZi`Q7s^HK!r zC*u~c`UCq6_Skjxs$Trkvu?hEeS^5S{7rY2b z@XK9*sOx zeAnP#HL;}U=W;@9tUv8A``j=t9UgvqXkr5GlW|Gdnv=seJf7EUhqEsyYKmdCf2f%X zUl@nFgTa_jE;oJR+TO>(8Hs+k;Uce8;_p;xt%UT^`hz?`GPA*4fWaxHS_TG* z^>|wx(}$2vpoFP(^Zi{l{D1yi^*co8_Kt>vaDglgvv0px}Fq zrorpvW1;2TH*xM=)wAo@ZXk^?lM5^q1nyYFD9HEfxXR(uN=OI!ENVBRn7Mz zs4c^bb-#J9f^8A&vRrCOa`8A_H5ihNf&E0vU%$8dltp8@J6QIPp;Ob{G0TRt;| zje2bMhR&F=miK=XcXGIY$46B)-x>zCmlQ{eTC+7P$Cx5-uW)OP9Z}oqV=pe~W&c2W*SRk#{@565Y;lE6;x(nRW2}6|c{q!35@7ff; z+SrH7{5);y&dD3rU;C2q@847q!{$`Oka5Bo(>$7l($V;}`xULDWurM4pOj|nn z_{1n3?xvJ7vs_++QGSP>!j-&|CZ5om=QYat+L9MPxL&&(^tL^xE#qR6jkfBTp0nGO z-LPZHl>Zc8pO&%jn(34LdaGzsgirb3tsUx6&=0m3($87OU0uv-=E<7v2#p@%iZ%<< z#$Ex|r_-YYQH4jJ8mtb;RPWRgZM3!_e7No7uM*5w9v?@`YB6{t)V5{dRTP;AwvFRY z1mZyMRB7z1|GUV+nJR$k`w@r9w`WWwytP1`;T6yIn)yTdbv`7EMCLyp>C6;BHNy84 zpoegh{vOE1eMljf>Acr@P0sP0Hqktl<^;?O|4QQkMlPfahaU$O@j0Pyy>SUg#K5zT zZ;2O$=ks=&T5Be^H1w~p&X7o#%D6UV*tH<_DBqk|RS~b) ztBzTbEpQgN!8GrFjp%lNh1#01+|-i0$2WiCy@8~o;k!Bl8)R9rKg)5Tl|?8SH~6P2 z3c#Y6tP*fN)7i&0^=q5ZlE=1tQA%r0NJ~Ncf7J5Ibx|^oM9?Sw%w{D3vT3;Wh3)v= zD&@F>%=k}+jmVbJcO;ED4%&^s9O$}N&#aua;vlpepAI0%hEb#ERX!f?-QHe#B88OL z2DZI+*(R3JbM-`GvzWZGd+GEqPKY-37WhMP0z>?LZhoJUi!DW%t!bon+X9V>Lfm|E zN~3&;2Fnzh#gQs&JIzjVLKM~#bW_zf)T^>G*d5%(%Dh{)H8GaqJD*K#mpR&}Q~<3h zWmq`FSh6JB4{uF<%pO?(#X(Fkud6=_<52y6yNJ9l#ON78HiY(@x~J$Zn7ubvpzhdr zM2`PMCkm#Zr{0KrwduOmR4fw6^X*U&db}12mpI`5S7Pzm_4r=egbG=9K8n0Q!_SqE z3hpJWgX4Px05sk=J~rCc*>UT0qS;z*<(YAMkY<6x1sg|7{x$Y}Z_c*ModXNX?yDEuvqp62N ztx4{T9t8P*KVx~|5^xyJj&RMMMMdZBI4w$){53s~7y31!aA!Hpzsz)UUe3rxolP&c zXKSeNC24C4K8a|Zx9)g5)IR^#CCRv^l8Ls6%wdY!P^=;C^G%1IrVI+dw~$=hpL@GeK7Z$n#6D>^8cU9>+!6ACHbLf zFVjBVK^dzVQ?qDsvrCtDcN{#L#YK0c#UW~1M6OpQ-HF)1#MJ07qW#(1feAfJdK*ln zK<3ktVrcXIfs!{d10vFVTb4V zoJc+kM>LE!ncmU62F+}p`|>^aO5W5ilJk19$tM)&rZ+^Z)hBhSdp!>mRD}%IQ zHrqvKt?f7QZ#;~xqJ0!8{SHkF4$W#=Do~Y0t+6{d)`&r-Lq% z6hq{pt*Poe_DUcT9hq-Je&UwkI9R#))`U%`;4Cu4>%IU0G+~nKV16!|jj0RDtrY^V z8A8Qg{$dwu^j9qyD9n9Nz2x7w&Bp7qtJFDUey4H4Mb)i-lyjDlOD+wb${Tb@R$KZQ znma$b`i4(0O@EVwk5SXIWC^oPfSmUHMuwx6w+%|HS)8~PTIs=Fc8MM zLj>Mi@W#&czpnj{32VsweI|hvTShM)^(GHpx+l9C40-~3wT**OswP6gUWCZO{?I;>lruQ zMB9d6S9k9J>{XO+({;J9QcmiTCbVgbEW2N73*`49)`)%|Fy!xVX-ASU7il%JQi9yu zC7#0}4F)lPKeftHg?Q~hJuQZ59E{q7FMOJB1|b_K)~`=Q)0OL;!zoTEQkzB7C+ytM zbsW%(!z~JnPQeB;c%#Y8P6o=#Q0($lInCrE--xcHKG9ujk$wv~Nh(q7Ip#?0OpCxP zxBX8{cnuBRMj}v4dafZEO;0u}_A0#{^BgyMGVEtDPhflZz9uJwW`npeo&Uy=e}0cC zLL35gFQ*-V2YnGLw;`7eAw{B9SOi{$QP}%- zsc9iOxs-aAPRiL<0hE1gGZg73AI|KXbLiAmJdt%Sk?wiOEMa7ozglHIEAP{zSNxb# zW%7qd-28_^$8s57GPz#4?*d22b&NW?zW8JCBki$KBe_~b!fMCh?gtCOXX5_6u*sE& zeVT09ULP^@(LOYDvTlxwH+fknA)Pjh{akv|oy)D3?-_nPv!Me6RIHMq(XGqU*V^=` zhjimMe~~dep8pUntQA}uFC62%Up77vQn*Hl0sL;?+y(;Nh`4${`bE0-n>tUouZYG;%0?FIMT!_17h4G?_@7{68 z+8Gj~q<=C_=O|cLl$avHGdba0+56FTrLi7**G`n&WLDrG14i7@zQ&iVh!MRmU06hO zZ$wkqJoDPgPEcBz&`%3!Bb#Nscq6Z}RZlyq2tR0lR&;d`2iph>7QziW5l#NEX4Htq zXV@sxTphJ#bDamqbkk5M+Qht-;~QUGN+skU50|VUOT*gA2qQT^Ca%8B7;5tOixfFO z+33e9>SSaZN34E})e#nu=p=UB68O5Zc_i$fje>t9hr+hHnO*wFPD_NL$5SU{i~O?i0N0} z%VI1_mrt$Q{2sr2v*Fd-q`qcM^z9Vi{o<2E(*e>#l7bt8_-velh$TOrPf8tv3=Tu( zpv41&TvX?^qYaexC?)b%e8q^aXDjn3+w;^A{gR!xsLfvxzE7~K%9?o$?;0ZT8X@dw zG+AbIT@3oB+NJpA=-3g6^nN-MQ0d+{F(&%BD}24Y;zXVZ_Z5HT_+yRY@w}qn)u(V> zKWX-lT+};!ZH4s?3ETNHPSy`ux;z5qrgOaiCY~Qbg6VP;ubJuH$j(d6R`WumtiDUObQvKjZ;4(S={h&4eQ$-DgP;d@T`JfiQ;AZT5;^Q3FJm!;WD+xAhpkMF5rV>8apY$)a-huRbtd{?F$Y%G zQ=czRu$2EDuaCj+FV(X9*xrx0I^HJ^;PX^|N4)xQOBDP3iKmd6v*b+C%SF3NCN<+v z_Iyo?2rxwJ1kWc)q`-S}G=|ZaE$y1?rd+g6yF$28@c+0tGtBTHi7ZOB0sht&v)@6y zZ7BD1PZ&m&Zj$|F^oKwMjFN!uTxJS5rCoC;@s+Qnwl(#1p*J6MjP_4vG>nxA0Q(XY zTpCN`X3#z@@mZk&{P5-^8EhH&8=4R%h#5h^>86>-1M_@wAZ3-$lOfol!BmnH`Ph;w z$UME|h}W&ileJ6^qegB@-lOO^6ra*5zct^Le?I_8_u;!WmWU>1;#bKRw&A@egTkla)lnKLT*^?QqDi06k~H)yL=h?OoZ zsI9zBq}W)S_qoiOzt7B~SZ8MjtIWn_BF&P|8RDqRPY8D3zy6|H?A?5ew|Lem3z;@g zrH9{*Owo}$4ZVHHB&qg9JR%4quJBl*FqWU-=>Mc0zDqH>Kj7Kl2nZE>aO>Ym!!+=a z=x)-iQAT=WVY@`z^Blwswdu3Hz=Rjf_c?{lg?!cG>a3u3Ddt~4@YaR zKKJ^W2aw~wX{bJue~_tLiML_4`&iqDSjM_diI&WIiEbABkJC}+ZX|g4p?EzpWKQ74 zo$u3l(Rr#FPNIX8QvC{4A&70NOTvU1KZU7RB)CLLSJp_NGKwRp+>x{?p*On;H=o;a zxI8^A7EK^(;?2Jp8CZQ`f{b%mc-y>b0xbuoyBB2*iM#M>#vb;K-x#7H4ZxbEz#PSv zQ_`E{&~IW=7Qy>8-e<~W@JHjQJ&I)&nopsm^`Z6u}5hvq-*u+KI z?&&~o+UuasH8Az$jcE6LnwScGUr!qyUmZofz1i~m)>Q>uhibiGy1Rgum~{a+FD<%D zdzYv7TjD4FX1gxi>U$Vro0xwP+5gv9&T!|Sd^&FH&R#Tk%Gd5Ks``D1I!Di52Hl?5 zzHQ0ZD4(1&%RBw8u3j-kG!&?6cQlHXg0kRk>FuJGn#pB8YJtaXRAM^u;#TN3Q~!8^ z^$6}qd3_Jz5wl^`{-=g49yrGIaYq6aJ_0}?DLZxj{G;4B$Tfs8UDH|!gJ_P=#P@ER;w`P zDij$>Ut8!2t6IQRAlukZPTb_fbXMAHa`8fp0*ME5S~b9DY=;kkaAKEtiXCq-_=H-a zkI_-Yfjll~&@OajAHmx9(XcfW1e8Df?mSN z7n+%m3Bgl5{Ax8*7cFUgh-`!3vzyO2n++9V;M|i~;3wKufoQ{S@^fYhngp0dtYeh0 z&Z*Mjybp`#dQ=YR9g7mDkH>{*uu8Cjix{eEmI+(MB?+oMc^BHw5`lCge19&pOupxx zwzP?MNiru*9)Nb&~lPJO-uLdN&c^o4ck3ug#d} z{f>>Ud$pGdZQN7cVb4TYa?&zv@2sINi_@%jqiKYjimJe9guA%9{-k5 z9olKXy(SrpX&sMF0~r)Z9-{y-^C>P%l9tTB3sos!02yo!TfFUzy%o{U8g5Q5!3HN1 zuX>wEXVm;#hUAyeJ3)Rjv~9tZaDC~ zMXC$V=Lutn4DE#eMJDC|j(8aO8k_>$gH#*M=kVCv>^qWUqeDECdS`$(Bk*)4n~LAXG>g){a<_!ci- zW1NU9tq1+;n)PqQm*LK14hHPDNU~0eT37N^U;+kpoH0ssXj6) zJvS-Y*0%_#K@#o773M~Y8i!L87EuU{vG0X{eD z&3)Ce3XoX6h8o)%I)5+Fyce8Y-JT#wAR}aUu2GbXcgqi%l;V_vdu*;*Pl?-;B zi25I_KnOQAvar0bUxllY(!PR3RJylrd1#z0VnqMP6S{G}_$%hK8d37cWxPD1k~h2R zNIBIh5KP1AiM&H>O<)S7I2a#K53+m?5K-QoM6TEfs(y6JwP!X$@Roy9eZ(D|GB{D3 zrQ)Y?J!liy84?zpFT?uAJA!e(bmx144jiL<24dp@oN{z{c ziwwUOR1Y19WvL)h5gLoHrr56DTcJ!?h6z(DG{qaby7}>2{s&78LfN5{zHdW{A0BTCNcqSx}_QS#NL5Hvq|tr0IaiWV7JCmQ4y^C zoJyt0Z%LQe?!C4-4WAjMeDnL0b59e2(C#3z?$#0Z_?v`s+ZF2fazaz!D(X#YB00rY z?iGYf#Sxssa22kQ6ur2yv!~2s_p6aqb5Sh>#nu0@WCd&hpoI%U`EsWB@wc?!$@SFa zV)2@ynfH4NkeIh5q4w#&CVh?U#0VwIpTDKG5O5eDiVMVrK>Vo3j?@6=%H%K>aG#ju zGC8C(MWe|A5|fpSLO;2|Fb_?0qQ;{}8X-87{d04%5wuYbGsv89=ZNHnxs=*^s?*WP zWAN~CGCu`M=B{=xYq%LH2=lf%XFe9%#!6BkoQc1iD}g@Pfh&-Q@!4Y{en3Q}Y$hZ~^8H2pMTP2;Xe1b{Pa+lMseen58m&jP;y*NRTN^ z&@~Y{zE(%qxB1G>!=nUg*DZ&SM4}-StdJKOP%YO~p@Mt}_HuHSGnD8JBR($83oUpY zt<`Y<(7Q;=X;^nnXOg@vH&f^PBg27(6HfRCA?(J-ri z`#=1iG@8Wpfw93x6UpS&vb47+B-iL=y^F8@uIuh$Er1(udad&VQ`=vDV=f5lZKKpN z2`xoUE_W`~R?0Ytm0hUP=P^7HxEAl*{FS;c?Q*j6ZPL00WLzRJ$fWGo`j2^{=-vys zO;2VcgZBYR=<2Asz1-rLp|hK^$Rez4sg$zd(gsY&Lt7&xLx*lJW<2_s}g$oXfuOKw) zCOLcJi}HT+3bvsaoZ!6$Au#szC5dHT8_T+7bOdI?)5v9AScj!ifTXfM4okSGvO?sV zoBRzjKXf?FLk2xsJm2~0PT_8x+E=eJMElRl&xt7umObZv=Swuh z&5qj!vr?P)T~mY?Ie5 zl)2N*x>nNZ9vXVU8&ypfGAB;=IcS!W>?mPply^83wMh9!H5C<0dBBr3Yr^yI5 zA~lw^%n~Iz+Of%kWZo5jq9%i|BA=k9>HB~i(n)_&Z`eai31EV=wZCy@&%6A=-^~c@ zfi~kZ(mpT*UBW7|D588WBOE`R_(SOL5X!9H#YQm*7b0``jBRj-5Z*y$^d9!39Fl@= z;F7Z7D7Cc38}obfrtVcUY??BH9a~H#kiQe{f}%*yL(m12rb|E1P_1RR;g>WhCde-HAftlo)N=zs^1&9{KSE3G;AkS=0+u?&FTEfm$z8vt75y!Nlg{mCxJ#fv z^o4qGw~IIIsm^vF(%Kchqr7G%k)i*UifHv&x7g2xkUyENnjHqQU`~tJuIMagWILvl zp%Rlw!ucUtnb-tRkPU`|0oG-UJycW;sTG|7Zc_&POA_8^J(2V;g)^ROHD)-gh)Zne zr=000i$a1lB5JNW9@9ziRo=+wB(n?|6$cR|8(Ev!{a;CA)#}?6=t>Cf(|zh#g-EBW z_(0Pr(wni6FjQLIz$~*+TcHn}<06X8L_+dB-!7Qhi9g{dfBbm~b!+a9YwX!oPdt`A zR8$z$<|>6(fWlG#o)|PP`%ogFjwXN#$)0J&q;$pGW4N>&d}WcVqwl|lrKjP-7cM5e zb?y=Q^xa=(uM>av0x^x~QxYz~=bNkcq$wrwHkVMku#2pbrFP!^$7@&r>V97WVJtR@ zFvW9{Fxf=>!L~kR&$Oi2GmOV;o#8U-Wf%9{S+iw%qDLn0TQqvy14SH$$f8dEQ7JQ= zxw}i96S>){#Hrxpy%u4A@^K&b1zV@{(`B!+0wcO%%O8ymE8;;%2UF}Da%?PeY`8{_ zmSu0APNBa+KHm15Un5JoUzdE)e;6B`*=a9lsm3t!I7@?( zBS1!ikilC3h}1WPk%BVnJ~AGe+@o#@mmOnV-_c*J`%&LoQ~TTqN*zD(a^3i3C#ppz zN?EZ;NB{$5Rcp)2uhKbSsb>%?Jg)UDIQjl(7l7wFi1Tb{^3lj=YK`{e*;X&(TaYWh z+<7b)gufEXm~4j(j{`|WK#?(V!9=h~4(knIh^i$U328DR`nzNh%nX{K8MjNhT7)8R zv-n$-E;x&yvKUwq)aa6Y-OzyLJ`8r&0j@%0MgV!_LOZLrq+!MqqJGTb3lOK53^zgYVX=6fz`#1gJ|XM zNV>Fi61nr)|^T>#EL_<xl)iufO6p-$TV$I@SjC5zHi z=$}$T`ojFG2;gt4B1fs>kgEV7L~nHbjZOr-w!f?dHrXVF<7CF%;GoIry-He}vk(Qp zw_dMR3Lrf@o^-}6R@5M@yj3YBR>0W}c75FALg)CU*m^wgmh{%#0?F*7FP z3GLB99?eY?k;u9M$@;Rba?j}GAjIIra|on(=&RT4C0@4hlg*#=VRWWohF&+Gm)+4u zR!)kWjfCXe9Ta9|VpNLhrx|kghk>@TejW*k#F|rk6Q`0BFCqkc>h{dEtx|9l z6Cl4swgywT^f5^9Od8;EIV!)sJsrQDvv;xLJDZFQtKh5o|G3%h6b*Ha(b$;~dD%7f zlsVGbTJ*d~^gK1$1>tz6QXaNGL@{^$b91}VpkRo_5-W0zNj-mYJ3o)>b<#TJWX6Uh z=24V33xa4!a0eC=8Hwe^gh)TPaV&^{V}!k;{#Mr$c-oZBPcgG$Gs*X^`_{$MUK4PZ=`P zrJt!g7DE0f4|(nDmNh|MUCA?$Hxf+~YaK|lEG{4wtN0**H&XnC69;gFw_rU3Lir=2 zh#KbL?qk7*(!$ku4^Y0}&yA;EQ}}ysN_Tjt*ieWa=FaApHAI>NeQ(C^T*c5!a4Cyx z7XYOOjCI~CKh=V-g^c>r_~Wxk%xAn3Iikcz;;;4H4#+@E3F%BMfuQ_L0IR}$#@DZu z+L2+=KfA4}K%rYz!;_spCGN!gE^pwsYT|2?Upb)vYAL!1aHn}^%X3c!Bc4641Dt0e zT8)p~+@mhvC|oE_{+eg~PRt*`19G)Z7N53eH$FYYO5=CYwDfy6LY&a^UrG%Xos7gc zRN@Q3hc1iG?Ke!AK|t^%TfyRf(BOc1lp#BaKFqIAYvS?gpo_&j6jlTv?I6189*Jj5 z3*S7%H%)U#wIZsDT5jblX0&{srJEdi7`9SeX;)D^lv``ZYn_8Huv>PeiV-~Ho*58* z3TiF2=uFw>)in6c2_%ok84qwnvFW3lH>rlEVTB}Y5 z5OJL~HPoaT4;3ACF3c4%}vMGB^`-cbrw z?{RQlzkbYqRP60NVpWj!*>z&1_et*`pyGak_G1aDE5_Z&5Tgw4i^*lLMw;IXC5FE} z!z_VfH!&;JFS$=A%EKFlC>gjV>_Uw!zHn`1a%zLI+u>Cl!$Z z5yfvcj$1l&IEUb!V3bn!?3UcpY3UyKaYB*9>VW)o24Ro&w}>3J@xyUsimSDfnmh4{ z9Cq^!uy&bZO9p6JWbQR#1w!JtIDpQ?D4vpwFfZFv4L)k0^n?m$<*pgW9Td zwgs4Ln3%i`JmY@A#cfYXlrpswRUuZ^gAGxT%9~n_BAG;jo+Cez)8CLnR4o!bLT3KMcBlSt&~Koecdw zSi;v5>7lOcrA?3MQOj?y-S6WQ#T5=GJff@GK(~c-N`}TCnKA$e75Y813b(X)4wr^M zaP_`YOOfxQls5CXLK)746k&WX`lC}KE=5BC=drra-f(#Vox#2Y>RA)U4_o!N_^K9x z7zEl%%nFWzS#B3-da05+ey(|_oA2@8TF}^kUr@h&nbX&n7}~9N6NKr)ZJl@O>r-6q zP`l(5-q(~DED4J>CR*&$yC>-ZzL(~xJ|Spx6YNl*u-JIeAAEhAxiF{)^w81!S1G9O zn9r~zb9AkRjD^Ei>NWn1rQun~MoAvsB5O2zh-@z6mH5KEPUcA=1hT}akRSV%0A)Dz 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 z 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 W*`4a8a>;AJKk*kb&vS)!ef|%)L*PsR literal 0 HcmV?d00001 diff --git a/package.json b/package.json index 8a9c37b41a..13cdd0da5b 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,8 @@ "workspaces": [ "src/backend", "src/frontend", - "src/shared" + "src/shared", + "docs-site" ], "scripts": { "prettier-check": "yarn prettier --check .", @@ -59,7 +60,11 @@ "docker:i": "cd devContainerization && docker compose -f docker-compose.dev.yml exec -T backend sh -c \"yarn install && cd src/backend && npx prisma generate\" && docker compose -f docker-compose.dev.yml exec -T frontend sh -c \"yarn install\"", "docker:test": "yarn test:setup && cd devContainerization && docker compose -f docker-compose.dev.yml exec backend bash -c \"yarn test:backend\" && docker compose -f docker-compose.dev.yml exec frontend sh -c \"yarn test:frontend\" && yarn test:teardown", "docker:rebuild": "docker compose -f devContainerization/docker-compose.dev.yml rm -f -s && yarn docker:start", - "db:pull": "node scripts/db-pull.mjs" + "db:pull": "node scripts/db-pull.mjs", + "docs:dev": "yarn workspace finishline-docs docs:dev", + "docs:build": "yarn workspace finishline-docs docs:build", + "docs:serve": "yarn workspace finishline-docs serve", + "skills:sync": "yarn workspace finishline-docs sync-skills" }, "resolutions": { "@types/react": "17.0.1", @@ -153,6 +158,8 @@ "build", "coverage", "docs", + "docs-site/.docusaurus", + "docs-site/build", "lambda", "node_modules", "public", diff --git a/yarn.lock b/yarn.lock index 813be6d6e3..0d830a9da3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12,6 +12,198 @@ __metadata: languageName: node linkType: hard +"@algolia/abtesting@npm:1.14.2": + version: 1.14.2 + resolution: "@algolia/abtesting@npm:1.14.2" + dependencies: + "@algolia/client-common": 5.48.2 + "@algolia/requester-browser-xhr": 5.48.2 + "@algolia/requester-fetch": 5.48.2 + "@algolia/requester-node-http": 5.48.2 + checksum: 70c56081c26684e8b12cacb292cd2ce8cdc5763dab26bd43449ee11e0788b035786ac87e42684df98adfc783ddd178c0fbcaaf2546b7e162904b0337e7f95bae + languageName: node + linkType: hard + +"@algolia/autocomplete-core@npm:1.19.2": + version: 1.19.2 + resolution: "@algolia/autocomplete-core@npm:1.19.2" + dependencies: + "@algolia/autocomplete-plugin-algolia-insights": 1.19.2 + "@algolia/autocomplete-shared": 1.19.2 + checksum: a23def50bd74da864dedc1286b954216a8637cff6b836bbc199b4324072ba6db84ec51b562f7983d75144d9be0b17b8cf65ceb8ba1b1255e88eb89244ce5a9bf + languageName: node + linkType: hard + +"@algolia/autocomplete-plugin-algolia-insights@npm:1.19.2": + version: 1.19.2 + resolution: "@algolia/autocomplete-plugin-algolia-insights@npm:1.19.2" + dependencies: + "@algolia/autocomplete-shared": 1.19.2 + peerDependencies: + search-insights: ">= 1 < 3" + checksum: a6e4d14ba86edb12b3006355058b1b674abd3211b5ac9a469f859c900737d8a3257cbad7b399eba087f3153b12dced97ed281c8c0c6f70873528240bfaaae9b5 + languageName: node + linkType: hard + +"@algolia/autocomplete-shared@npm:1.19.2": + version: 1.19.2 + resolution: "@algolia/autocomplete-shared@npm:1.19.2" + peerDependencies: + "@algolia/client-search": ">= 4.9.1 < 6" + algoliasearch: ">= 4.9.1 < 6" + checksum: 34803e0de6b6e08352f46daa9b3e566204dd438f3a84d6dee5c808676d4281504b6cf320a25eaf5e7bd8ab9f7cf47fbd771412872e02349c65bbdaef4580a11a + languageName: node + linkType: hard + +"@algolia/client-abtesting@npm:5.48.2": + version: 5.48.2 + resolution: "@algolia/client-abtesting@npm:5.48.2" + dependencies: + "@algolia/client-common": 5.48.2 + "@algolia/requester-browser-xhr": 5.48.2 + "@algolia/requester-fetch": 5.48.2 + "@algolia/requester-node-http": 5.48.2 + checksum: 8050495b02afe5e0ee4471a237e5fa0ca0751d79a5523fe36fed4ab81db7e497ac1e3124ae004a3f18bde5acae1f3277221ebddf2d0a6e3a73ea75f4c6ed93d9 + languageName: node + linkType: hard + +"@algolia/client-analytics@npm:5.48.2": + version: 5.48.2 + resolution: "@algolia/client-analytics@npm:5.48.2" + dependencies: + "@algolia/client-common": 5.48.2 + "@algolia/requester-browser-xhr": 5.48.2 + "@algolia/requester-fetch": 5.48.2 + "@algolia/requester-node-http": 5.48.2 + checksum: 628012079562169eaecb27e93508e93ed103b809f42a1ee6206c2098b6c1639350f72194ddd76b059af2802d39dd166f4ae61188d2646d0bbd22194d39d80302 + languageName: node + linkType: hard + +"@algolia/client-common@npm:5.48.2": + version: 5.48.2 + resolution: "@algolia/client-common@npm:5.48.2" + checksum: 8dd80e5fdbcc23b9619948d5fed6a36091a61d106a3340edc8c0dbf2e20e20b5fdd2874322557f876a01cce788a2093e2515ea868892eb8a9bb84a4e5c81e677 + languageName: node + linkType: hard + +"@algolia/client-insights@npm:5.48.2": + version: 5.48.2 + resolution: "@algolia/client-insights@npm:5.48.2" + dependencies: + "@algolia/client-common": 5.48.2 + "@algolia/requester-browser-xhr": 5.48.2 + "@algolia/requester-fetch": 5.48.2 + "@algolia/requester-node-http": 5.48.2 + checksum: 2635e4444ba37409726b7c74ea36f19ea54a13b8f1274d9dce857a060b71b8a2a29210724244d1fd4438a156577e96e1c9bff7fa4bd34a9119ac3390a06ac2e7 + languageName: node + linkType: hard + +"@algolia/client-personalization@npm:5.48.2": + version: 5.48.2 + resolution: "@algolia/client-personalization@npm:5.48.2" + dependencies: + "@algolia/client-common": 5.48.2 + "@algolia/requester-browser-xhr": 5.48.2 + "@algolia/requester-fetch": 5.48.2 + "@algolia/requester-node-http": 5.48.2 + checksum: 69cec8e93f2c9350b411ed3de861eccd1055e30f50e4b810cd072de319bd9ddcfa02d41737dd3689267f649cb60eb7b443f3dda1c957044c6b02d735fabd7fa3 + languageName: node + linkType: hard + +"@algolia/client-query-suggestions@npm:5.48.2": + version: 5.48.2 + resolution: "@algolia/client-query-suggestions@npm:5.48.2" + dependencies: + "@algolia/client-common": 5.48.2 + "@algolia/requester-browser-xhr": 5.48.2 + "@algolia/requester-fetch": 5.48.2 + "@algolia/requester-node-http": 5.48.2 + checksum: 15abc1a8b94fb2df56f75e0fcf2c504d51a060711f00e5bd7d364529c63956278d83363107068a0bfcb4a7fcb4227d631b2314700bc7e84c04ee76af68e93add + languageName: node + linkType: hard + +"@algolia/client-search@npm:5.48.2": + version: 5.48.2 + resolution: "@algolia/client-search@npm:5.48.2" + dependencies: + "@algolia/client-common": 5.48.2 + "@algolia/requester-browser-xhr": 5.48.2 + "@algolia/requester-fetch": 5.48.2 + "@algolia/requester-node-http": 5.48.2 + checksum: 8072d6c0b3176c02f09abfd521f2932d7f826f1b24a835bb29bf0d5486668ca0a5d5f7cb66233f611ab682199035a1a84df7d81cf4ffb75d55b74b05fa7a74ea + languageName: node + linkType: hard + +"@algolia/events@npm:^4.0.1": + version: 4.0.1 + resolution: "@algolia/events@npm:4.0.1" + checksum: 4f63943f4554cfcfed91d8b8c009a49dca192b81056d8c75e532796f64828cd69899852013e81ff3fff07030df8782b9b95c19a3da0845786bdfe22af42442c2 + languageName: node + linkType: hard + +"@algolia/ingestion@npm:1.48.2": + version: 1.48.2 + resolution: "@algolia/ingestion@npm:1.48.2" + dependencies: + "@algolia/client-common": 5.48.2 + "@algolia/requester-browser-xhr": 5.48.2 + "@algolia/requester-fetch": 5.48.2 + "@algolia/requester-node-http": 5.48.2 + checksum: 84dc3ac1dc01c93a2c410a0d4ede7fed15d095e843da983068440ab47e42a33da40c5982970cb37d6a324993a691a7421ea7fd784c44b40e30dc2513b48adf13 + languageName: node + linkType: hard + +"@algolia/monitoring@npm:1.48.2": + version: 1.48.2 + resolution: "@algolia/monitoring@npm:1.48.2" + dependencies: + "@algolia/client-common": 5.48.2 + "@algolia/requester-browser-xhr": 5.48.2 + "@algolia/requester-fetch": 5.48.2 + "@algolia/requester-node-http": 5.48.2 + checksum: 4a9692a24ea3ed4517998f942d0c83045bc897158efce3a992ecbb4c00edd134c95116dd089285339b532dd3b6f2dabe4feaf240fbc3221fb7b1eabfd5df0cc8 + languageName: node + linkType: hard + +"@algolia/recommend@npm:5.48.2": + version: 5.48.2 + resolution: "@algolia/recommend@npm:5.48.2" + dependencies: + "@algolia/client-common": 5.48.2 + "@algolia/requester-browser-xhr": 5.48.2 + "@algolia/requester-fetch": 5.48.2 + "@algolia/requester-node-http": 5.48.2 + checksum: f1fa8d251ac847fc3ab9b20c536b7ed357e30a6268c5934fa4ed8facfc0f6b210908f8236773a95bbaf98258fc98b732d15686dd1d908ca6912ab4266c7e7341 + languageName: node + linkType: hard + +"@algolia/requester-browser-xhr@npm:5.48.2": + version: 5.48.2 + resolution: "@algolia/requester-browser-xhr@npm:5.48.2" + dependencies: + "@algolia/client-common": 5.48.2 + checksum: da9d0986257c9aed91d0a3124e21f6f78024f753e49cc202192ac870029ba41c638660ed6e467bde44d3cc07e93ff0374088b5e7e02031dd8289e5cd12c7c637 + languageName: node + linkType: hard + +"@algolia/requester-fetch@npm:5.48.2": + version: 5.48.2 + resolution: "@algolia/requester-fetch@npm:5.48.2" + dependencies: + "@algolia/client-common": 5.48.2 + checksum: 779da5a1a00267ae865868634f15bc2b9f3c97e9c96a3b3c900bc99cecc914b926c9300fc373f9ff0787ca83a7a0dfc51a61cbc8b7f63cfdc52d610ecf8b8172 + languageName: node + linkType: hard + +"@algolia/requester-node-http@npm:5.48.2": + version: 5.48.2 + resolution: "@algolia/requester-node-http@npm:5.48.2" + dependencies: + "@algolia/client-common": 5.48.2 + checksum: 7f7b0f762dabc1acc6017171c14859915038ab7c8260a0d1c128212fc0c1f2c1e8d56401c751bb4f3f9b343132dbc451abad2a9b322d3216b10c4887fb5c5526 + languageName: node + linkType: hard + "@alloc/quick-lru@npm:^5.2.0": version: 5.2.0 resolution: "@alloc/quick-lru@npm:5.2.0" @@ -552,6 +744,17 @@ __metadata: languageName: node linkType: hard +"@babel/code-frame@npm:^7.29.0": + version: 7.29.0 + resolution: "@babel/code-frame@npm:7.29.0" + dependencies: + "@babel/helper-validator-identifier": ^7.28.5 + js-tokens: ^4.0.0 + picocolors: ^1.1.1 + checksum: 39f5b303757e4d63bbff8133e251094cd4f952b46e3fa9febc7368d907583911d6a1eded6090876dc1feeff5cf6e134fb19b706f8d58d26c5402cd50e5e1aeb2 + languageName: node + linkType: hard + "@babel/compat-data@npm:^7.27.7, @babel/compat-data@npm:^7.28.6": version: 7.28.6 resolution: "@babel/compat-data@npm:7.28.6" @@ -559,6 +762,13 @@ __metadata: languageName: node linkType: hard +"@babel/compat-data@npm:^7.29.0": + version: 7.29.0 + resolution: "@babel/compat-data@npm:7.29.0" + checksum: ad19db279dfd06cbe91b505d03be00d603c6d3fcc141cfc14f4ace5c558193e9b6aae4788cb01fd209c4c850e52d73c8f3c247680e3c0d84fa17ab8b3d50c808 + languageName: node + linkType: hard + "@babel/core@npm:^7.1.0, @babel/core@npm:^7.11.1, @babel/core@npm:^7.12.3, @babel/core@npm:^7.16.0, @babel/core@npm:^7.20.5, @babel/core@npm:^7.28.0, @babel/core@npm:^7.7.2, @babel/core@npm:^7.8.0": version: 7.28.6 resolution: "@babel/core@npm:7.28.6" @@ -582,6 +792,29 @@ __metadata: languageName: node linkType: hard +"@babel/core@npm:^7.21.3, @babel/core@npm:^7.25.9": + version: 7.29.0 + resolution: "@babel/core@npm:7.29.0" + dependencies: + "@babel/code-frame": ^7.29.0 + "@babel/generator": ^7.29.0 + "@babel/helper-compilation-targets": ^7.28.6 + "@babel/helper-module-transforms": ^7.28.6 + "@babel/helpers": ^7.28.6 + "@babel/parser": ^7.29.0 + "@babel/template": ^7.28.6 + "@babel/traverse": ^7.29.0 + "@babel/types": ^7.29.0 + "@jridgewell/remapping": ^2.3.5 + convert-source-map: ^2.0.0 + debug: ^4.1.0 + gensync: ^1.0.0-beta.2 + json5: ^2.2.3 + semver: ^6.3.1 + checksum: 85e1df6e213382c46dee27bcd07ed9202fa108a85bb74eb37be656308fd949349171ad2aa17cc84cf0720c908dc9ea6309d25e64d2a7fcdaa63721ce0c67c10b + languageName: node + linkType: hard + "@babel/eslint-parser@npm:^7.16.3": version: 7.28.6 resolution: "@babel/eslint-parser@npm:7.28.6" @@ -596,6 +829,19 @@ __metadata: languageName: node linkType: hard +"@babel/generator@npm:^7.25.9, @babel/generator@npm:^7.29.0": + version: 7.29.1 + resolution: "@babel/generator@npm:7.29.1" + dependencies: + "@babel/parser": ^7.29.0 + "@babel/types": ^7.29.0 + "@jridgewell/gen-mapping": ^0.3.12 + "@jridgewell/trace-mapping": ^0.3.28 + jsesc: ^3.0.2 + checksum: d8e6863b2d04f684e65ad72731049ac7d754d3a3d1a67cdfc20807b109ba3180ed90d7ccef58ce5d38ded2eaeb71983a76c711eecb9b6266118262378f6c7226 + languageName: node + linkType: hard + "@babel/generator@npm:^7.28.6, @babel/generator@npm:^7.7.2": version: 7.28.6 resolution: "@babel/generator@npm:7.28.6" @@ -676,6 +922,21 @@ __metadata: languageName: node linkType: hard +"@babel/helper-define-polyfill-provider@npm:^0.6.6": + version: 0.6.6 + resolution: "@babel/helper-define-polyfill-provider@npm:0.6.6" + dependencies: + "@babel/helper-compilation-targets": ^7.28.6 + "@babel/helper-plugin-utils": ^7.28.6 + debug: ^4.4.3 + lodash.debounce: ^4.0.8 + resolve: ^1.22.11 + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: 582efe522e7ef75228f7eeea63fd659567ce865365e3d4b9d94451825114a7f1c8b61791bbbf134aa1b2aa6ee37620b145e74879dace7568107057180153e72e + languageName: node + linkType: hard + "@babel/helper-globals@npm:^7.28.0": version: 7.28.0 resolution: "@babel/helper-globals@npm:7.28.0" @@ -833,6 +1094,17 @@ __metadata: languageName: node linkType: hard +"@babel/parser@npm:^7.29.0": + version: 7.29.0 + resolution: "@babel/parser@npm:7.29.0" + dependencies: + "@babel/types": ^7.29.0 + bin: + parser: ./bin/babel-parser.js + checksum: b4a1bd3cf46712e439286db9a4105dfa741b5a7720fa1f38f33719cf4f1da9df9fc5b6686128890bd6a62debba287d8d472af153dd629fd4a0a44fe55413cd68 + languageName: node + linkType: hard + "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.28.5": version: 7.28.5 resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.28.5" @@ -1044,6 +1316,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-syntax-dynamic-import@npm:^7.8.3": + version: 7.8.3 + resolution: "@babel/plugin-syntax-dynamic-import@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: ce307af83cf433d4ec42932329fad25fa73138ab39c7436882ea28742e1c0066626d224e0ad2988724c82644e41601cef607b36194f695cb78a1fcdc959637bd + languageName: node + linkType: hard + "@babel/plugin-syntax-flow@npm:^7.27.1": version: 7.28.6 resolution: "@babel/plugin-syntax-flow@npm:7.28.6" @@ -1245,6 +1528,19 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-async-generator-functions@npm:^7.29.0": + version: 7.29.0 + resolution: "@babel/plugin-transform-async-generator-functions@npm:7.29.0" + dependencies: + "@babel/helper-plugin-utils": ^7.28.6 + "@babel/helper-remap-async-to-generator": ^7.27.1 + "@babel/traverse": ^7.29.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: bd549b54283034dd3e2f6c4b41b99a0caba0ddc8e9418490a611136ddb01e62235f14b233fcc172902fd1d18eec6e029245d22212566ea5cb5e24c7450d6005d + languageName: node + linkType: hard + "@babel/plugin-transform-async-to-generator@npm:^7.28.6": version: 7.28.6 resolution: "@babel/plugin-transform-async-to-generator@npm:7.28.6" @@ -1379,6 +1675,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-duplicate-named-capturing-groups-regex@npm:^7.29.0": + version: 7.29.0 + resolution: "@babel/plugin-transform-duplicate-named-capturing-groups-regex@npm:7.29.0" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.28.5 + "@babel/helper-plugin-utils": ^7.28.6 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 7fa7b773259a578c9e01c80946f75ecc074520064aa7a87a65db06c7df70766e2fa6be78cda55fa9418a14e30b2b9d595484a46db48074d495d9f877a4276065 + languageName: node + linkType: hard + "@babel/plugin-transform-dynamic-import@npm:^7.27.1": version: 7.27.1 resolution: "@babel/plugin-transform-dynamic-import@npm:7.27.1" @@ -1543,6 +1851,20 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-modules-systemjs@npm:^7.29.0": + version: 7.29.0 + resolution: "@babel/plugin-transform-modules-systemjs@npm:7.29.0" + dependencies: + "@babel/helper-module-transforms": ^7.28.6 + "@babel/helper-plugin-utils": ^7.28.6 + "@babel/helper-validator-identifier": ^7.28.5 + "@babel/traverse": ^7.29.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 36fd7bcd694549effdbdf733c32f0c9dbadea052316ff5e0830b07482a60c8ff1ee79850efff05e8046c4b99c241832f2c5267e0ae7c721c531c8ef12930c4b9 + languageName: node + linkType: hard + "@babel/plugin-transform-modules-umd@npm:^7.27.1": version: 7.27.1 resolution: "@babel/plugin-transform-modules-umd@npm:7.27.1" @@ -1567,6 +1889,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-named-capturing-groups-regex@npm:^7.29.0": + version: 7.29.0 + resolution: "@babel/plugin-transform-named-capturing-groups-regex@npm:7.29.0" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.28.5 + "@babel/helper-plugin-utils": ^7.28.6 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: ed8c27699ca82a6c01cbfd39f3de16b90cfea4f8146a358057f76df290d308a66a8bd2e6734e6a87f68c18576e15d2d70548a84cd474d26fdf256c3f5ae44d8c + languageName: node + linkType: hard + "@babel/plugin-transform-new-target@npm:^7.27.1": version: 7.27.1 resolution: "@babel/plugin-transform-new-target@npm:7.27.1" @@ -1708,7 +2042,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-react-constant-elements@npm:^7.12.1": +"@babel/plugin-transform-react-constant-elements@npm:^7.12.1, @babel/plugin-transform-react-constant-elements@npm:^7.21.3": version: 7.27.1 resolution: "@babel/plugin-transform-react-constant-elements@npm:7.27.1" dependencies: @@ -1801,6 +2135,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-regenerator@npm:^7.29.0": + version: 7.29.0 + resolution: "@babel/plugin-transform-regenerator@npm:7.29.0" + dependencies: + "@babel/helper-plugin-utils": ^7.28.6 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: f48bc814f11239f2bfe010a6e29d5ac2443e7b1d8004e7c022effa111b743491127acf8644cfef475edb86b91f123829585867bc13762652aabd9b85ed6ce61e + languageName: node + linkType: hard + "@babel/plugin-transform-regexp-modifiers@npm:^7.28.6": version: 7.28.6 resolution: "@babel/plugin-transform-regexp-modifiers@npm:7.28.6" @@ -1840,6 +2185,22 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-runtime@npm:^7.25.9": + version: 7.29.0 + resolution: "@babel/plugin-transform-runtime@npm:7.29.0" + dependencies: + "@babel/helper-module-imports": ^7.28.6 + "@babel/helper-plugin-utils": ^7.28.6 + babel-plugin-polyfill-corejs2: ^0.4.14 + babel-plugin-polyfill-corejs3: ^0.13.0 + babel-plugin-polyfill-regenerator: ^0.6.5 + semver: ^6.3.1 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 1d3a5951396469372d954538fb188479b86afa8e02ca541da8f123250aaed8df65573b68f67087f4b15a5ccff9abc3a3fdb1d9a07fbb85bfcb807168d7364a37 + languageName: node + linkType: hard + "@babel/plugin-transform-shorthand-properties@npm:^7.27.1": version: 7.27.1 resolution: "@babel/plugin-transform-shorthand-properties@npm:7.27.1" @@ -2038,6 +2399,86 @@ __metadata: languageName: node linkType: hard +"@babel/preset-env@npm:^7.20.2, @babel/preset-env@npm:^7.25.9": + version: 7.29.0 + resolution: "@babel/preset-env@npm:7.29.0" + dependencies: + "@babel/compat-data": ^7.29.0 + "@babel/helper-compilation-targets": ^7.28.6 + "@babel/helper-plugin-utils": ^7.28.6 + "@babel/helper-validator-option": ^7.27.1 + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": ^7.28.5 + "@babel/plugin-bugfix-safari-class-field-initializer-scope": ^7.27.1 + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ^7.27.1 + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": ^7.27.1 + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": ^7.28.6 + "@babel/plugin-proposal-private-property-in-object": 7.21.0-placeholder-for-preset-env.2 + "@babel/plugin-syntax-import-assertions": ^7.28.6 + "@babel/plugin-syntax-import-attributes": ^7.28.6 + "@babel/plugin-syntax-unicode-sets-regex": ^7.18.6 + "@babel/plugin-transform-arrow-functions": ^7.27.1 + "@babel/plugin-transform-async-generator-functions": ^7.29.0 + "@babel/plugin-transform-async-to-generator": ^7.28.6 + "@babel/plugin-transform-block-scoped-functions": ^7.27.1 + "@babel/plugin-transform-block-scoping": ^7.28.6 + "@babel/plugin-transform-class-properties": ^7.28.6 + "@babel/plugin-transform-class-static-block": ^7.28.6 + "@babel/plugin-transform-classes": ^7.28.6 + "@babel/plugin-transform-computed-properties": ^7.28.6 + "@babel/plugin-transform-destructuring": ^7.28.5 + "@babel/plugin-transform-dotall-regex": ^7.28.6 + "@babel/plugin-transform-duplicate-keys": ^7.27.1 + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": ^7.29.0 + "@babel/plugin-transform-dynamic-import": ^7.27.1 + "@babel/plugin-transform-explicit-resource-management": ^7.28.6 + "@babel/plugin-transform-exponentiation-operator": ^7.28.6 + "@babel/plugin-transform-export-namespace-from": ^7.27.1 + "@babel/plugin-transform-for-of": ^7.27.1 + "@babel/plugin-transform-function-name": ^7.27.1 + "@babel/plugin-transform-json-strings": ^7.28.6 + "@babel/plugin-transform-literals": ^7.27.1 + "@babel/plugin-transform-logical-assignment-operators": ^7.28.6 + "@babel/plugin-transform-member-expression-literals": ^7.27.1 + "@babel/plugin-transform-modules-amd": ^7.27.1 + "@babel/plugin-transform-modules-commonjs": ^7.28.6 + "@babel/plugin-transform-modules-systemjs": ^7.29.0 + "@babel/plugin-transform-modules-umd": ^7.27.1 + "@babel/plugin-transform-named-capturing-groups-regex": ^7.29.0 + "@babel/plugin-transform-new-target": ^7.27.1 + "@babel/plugin-transform-nullish-coalescing-operator": ^7.28.6 + "@babel/plugin-transform-numeric-separator": ^7.28.6 + "@babel/plugin-transform-object-rest-spread": ^7.28.6 + "@babel/plugin-transform-object-super": ^7.27.1 + "@babel/plugin-transform-optional-catch-binding": ^7.28.6 + "@babel/plugin-transform-optional-chaining": ^7.28.6 + "@babel/plugin-transform-parameters": ^7.27.7 + "@babel/plugin-transform-private-methods": ^7.28.6 + "@babel/plugin-transform-private-property-in-object": ^7.28.6 + "@babel/plugin-transform-property-literals": ^7.27.1 + "@babel/plugin-transform-regenerator": ^7.29.0 + "@babel/plugin-transform-regexp-modifiers": ^7.28.6 + "@babel/plugin-transform-reserved-words": ^7.27.1 + "@babel/plugin-transform-shorthand-properties": ^7.27.1 + "@babel/plugin-transform-spread": ^7.28.6 + "@babel/plugin-transform-sticky-regex": ^7.27.1 + "@babel/plugin-transform-template-literals": ^7.27.1 + "@babel/plugin-transform-typeof-symbol": ^7.27.1 + "@babel/plugin-transform-unicode-escapes": ^7.27.1 + "@babel/plugin-transform-unicode-property-regex": ^7.28.6 + "@babel/plugin-transform-unicode-regex": ^7.27.1 + "@babel/plugin-transform-unicode-sets-regex": ^7.28.6 + "@babel/preset-modules": 0.1.6-no-external-plugins + babel-plugin-polyfill-corejs2: ^0.4.15 + babel-plugin-polyfill-corejs3: ^0.14.0 + babel-plugin-polyfill-regenerator: ^0.6.6 + core-js-compat: ^3.48.0 + semver: ^6.3.1 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 740eb61714f3671adde2ae4066c708837587b0f30ddee7fbf6c85ea5a3823f5dd08413b1ee5fcb1abf26ec6d7e31060bae065d7032d3a2f62a43c80232bb54e9 + languageName: node + linkType: hard + "@babel/preset-modules@npm:0.1.6-no-external-plugins": version: 0.1.6-no-external-plugins resolution: "@babel/preset-modules@npm:0.1.6-no-external-plugins" @@ -2051,7 +2492,7 @@ __metadata: languageName: node linkType: hard -"@babel/preset-react@npm:^7.12.5, @babel/preset-react@npm:^7.16.0, @babel/preset-react@npm:^7.18.6": +"@babel/preset-react@npm:^7.12.5, @babel/preset-react@npm:^7.16.0, @babel/preset-react@npm:^7.18.6, @babel/preset-react@npm:^7.25.9": version: 7.28.5 resolution: "@babel/preset-react@npm:7.28.5" dependencies: @@ -2067,7 +2508,7 @@ __metadata: languageName: node linkType: hard -"@babel/preset-typescript@npm:^7.16.0, @babel/preset-typescript@npm:^7.18.6": +"@babel/preset-typescript@npm:^7.16.0, @babel/preset-typescript@npm:^7.18.6, @babel/preset-typescript@npm:^7.21.0, @babel/preset-typescript@npm:^7.25.9": version: 7.28.5 resolution: "@babel/preset-typescript@npm:7.28.5" dependencies: @@ -2082,7 +2523,16 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.18.9, @babel/runtime@npm:^7.23.8, @babel/runtime@npm:^7.23.9, @babel/runtime@npm:^7.25.0, @babel/runtime@npm:^7.25.6, @babel/runtime@npm:^7.25.7, @babel/runtime@npm:^7.26.0, @babel/runtime@npm:^7.28.4, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.2, @babel/runtime@npm:^7.7.2, @babel/runtime@npm:^7.8.7": +"@babel/runtime-corejs3@npm:^7.25.9": + version: 7.29.0 + resolution: "@babel/runtime-corejs3@npm:7.29.0" + dependencies: + core-js-pure: ^3.48.0 + checksum: b892c0ffbc3e06a5b67da2002452768f184f60e24817f8472b2e1cc1e8499f3a47e6e4c20fe5568dad25419fead4954a30a015c6c80e9b1e88120d1a10b7f684 + languageName: node + linkType: hard + +"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.3, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.18.9, @babel/runtime@npm:^7.23.8, @babel/runtime@npm:^7.23.9, @babel/runtime@npm:^7.25.0, @babel/runtime@npm:^7.25.6, @babel/runtime@npm:^7.25.7, @babel/runtime@npm:^7.25.9, @babel/runtime@npm:^7.26.0, @babel/runtime@npm:^7.28.4, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.2, @babel/runtime@npm:^7.7.2, @babel/runtime@npm:^7.8.7": version: 7.28.6 resolution: "@babel/runtime@npm:7.28.6" checksum: 42d8a868c2fc2e9a77927945a6daa7ec03c7ea49e611e0d15442933cdabb12f20e3a6849c729259076c10a4247adec229331d1f94c2d0073ea0979d7853e29fd @@ -2100,6 +2550,21 @@ __metadata: languageName: node linkType: hard +"@babel/traverse@npm:^7.25.9, @babel/traverse@npm:^7.29.0": + version: 7.29.0 + resolution: "@babel/traverse@npm:7.29.0" + dependencies: + "@babel/code-frame": ^7.29.0 + "@babel/generator": ^7.29.0 + "@babel/helper-globals": ^7.28.0 + "@babel/parser": ^7.29.0 + "@babel/template": ^7.28.6 + "@babel/types": ^7.29.0 + debug: ^4.3.1 + checksum: fbb5085aa525b5d4ecd9fe2f5885d88413fff6ad9c0fac244c37f96069b6d3af9ce825750cd16af1d97d26fa3d354b38dbbdb5f31430e0d99ed89660ab65430e + languageName: node + linkType: hard + "@babel/traverse@npm:^7.27.1, @babel/traverse@npm:^7.28.5, @babel/traverse@npm:^7.28.6, @babel/traverse@npm:^7.7.2": version: 7.28.6 resolution: "@babel/traverse@npm:7.28.6" @@ -2125,6 +2590,16 @@ __metadata: languageName: node linkType: hard +"@babel/types@npm:^7.21.3, @babel/types@npm:^7.29.0": + version: 7.29.0 + resolution: "@babel/types@npm:7.29.0" + dependencies: + "@babel/helper-string-parser": ^7.27.1 + "@babel/helper-validator-identifier": ^7.28.5 + checksum: 83f190438e94c22b2574aaeef7501830311ef266eaabfb06523409f64e2fe855e522951607085d71cad286719adef14e1ba37b671f334a7cd25b0f8506a01e0b + languageName: node + linkType: hard + "@bcoe/v8-coverage@npm:^0.2.3": version: 0.2.3 resolution: "@bcoe/v8-coverage@npm:0.2.3" @@ -2132,6 +2607,13 @@ __metadata: languageName: node linkType: hard +"@colors/colors@npm:1.5.0": + version: 1.5.0 + resolution: "@colors/colors@npm:1.5.0" + checksum: d64d5260bed1d5012ae3fc617d38d1afc0329fec05342f4e6b838f46998855ba56e0a73833f4a80fa8378c84810da254f76a8a19c39d038260dc06dc4e007425 + languageName: node + linkType: hard + "@cspotcode/source-map-support@npm:^0.8.0": version: 0.8.1 resolution: "@cspotcode/source-map-support@npm:0.8.1" @@ -2141,6 +2623,72 @@ __metadata: languageName: node linkType: hard +"@csstools/cascade-layer-name-parser@npm:^2.0.5": + version: 2.0.5 + resolution: "@csstools/cascade-layer-name-parser@npm:2.0.5" + peerDependencies: + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + checksum: fb26ae1db6f7a71ee0c3fdaea89f5325f88d7a0b2505fcf4b75e94f2c816ef1edb2961eecbc397df06f67d696ccc6bc99588ea9ee07dd7632bf10febf6b67ed9 + languageName: node + linkType: hard + +"@csstools/color-helpers@npm:^5.1.0": + version: 5.1.0 + resolution: "@csstools/color-helpers@npm:5.1.0" + checksum: 2b1cef009309c30c6e6e904d259e809761a8482fe262b000dacc159d94bcd982d59d85baea449de0fd57afc98b7fc19561ffe756d2b679d56a39c48c2b9c556a + languageName: node + linkType: hard + +"@csstools/css-calc@npm:^2.1.4": + version: 2.1.4 + resolution: "@csstools/css-calc@npm:2.1.4" + peerDependencies: + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + checksum: b833d1a031dfb3e3268655aa384121b864fce9bad05f111a3cf2a343eed69ba5d723f3f7cd0793fd7b7a28de2f8141f94568828f48de41d86cefa452eee06390 + languageName: node + linkType: hard + +"@csstools/css-color-parser@npm:^3.1.0": + version: 3.1.0 + resolution: "@csstools/css-color-parser@npm:3.1.0" + dependencies: + "@csstools/color-helpers": ^5.1.0 + "@csstools/css-calc": ^2.1.4 + peerDependencies: + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + checksum: 615d825fc7b231e9ba048b4688f15f721423caf2a7be282d910445de30b558efb0f0294557e5a1a7401eefdfcc6c01c89b842fa7835d6872a3e06967dbaabc49 + languageName: node + linkType: hard + +"@csstools/css-parser-algorithms@npm:^3.0.5": + version: 3.0.5 + resolution: "@csstools/css-parser-algorithms@npm:3.0.5" + peerDependencies: + "@csstools/css-tokenizer": ^3.0.4 + checksum: 80647139574431071e4664ad3c3e141deef4368f0ca536a63b3872487db68cf0d908fb76000f967deb1866963a90e6357fc6b9b00fdfa032f3321cebfcc66cd7 + languageName: node + linkType: hard + +"@csstools/css-tokenizer@npm:^3.0.4": + version: 3.0.4 + resolution: "@csstools/css-tokenizer@npm:3.0.4" + checksum: adc6681d3a0d7a75dc8e5ee0488c99ad4509e4810ae45dd6549a2e64a996e8d75512e70bb244778dc0c6ee85723e20eaeea8c083bf65b51eb19034e182554243 + languageName: node + linkType: hard + +"@csstools/media-query-list-parser@npm:^4.0.3": + version: 4.0.3 + resolution: "@csstools/media-query-list-parser@npm:4.0.3" + peerDependencies: + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + checksum: dd7dc015a94e0832e5289794f6ab730d1c3fdc85fbd92433eb608dceb91e4977d345c08fe90c487359ce3ba39185fe15789d09c321c799f5c18c6aec7bd8da09 + languageName: node + linkType: hard + "@csstools/normalize.css@npm:*": version: 12.1.1 resolution: "@csstools/normalize.css@npm:12.1.1" @@ -2148,6 +2696,21 @@ __metadata: languageName: node linkType: hard +"@csstools/postcss-alpha-function@npm:^1.0.1": + version: 1.0.1 + resolution: "@csstools/postcss-alpha-function@npm:1.0.1" + dependencies: + "@csstools/css-color-parser": ^3.1.0 + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + "@csstools/postcss-progressive-custom-properties": ^4.2.1 + "@csstools/utilities": ^2.0.0 + peerDependencies: + postcss: ^8.4 + checksum: 40dfd418eb36fe87500769e2ee31717fc549eced3152966a4a5b4121e657a9846d14ef9bffee4faa3298a362d85af2684c3a4fea31bbca785205e7bfecbb94dc + languageName: node + linkType: hard + "@csstools/postcss-cascade-layers@npm:^1.1.1": version: 1.1.1 resolution: "@csstools/postcss-cascade-layers@npm:1.1.1" @@ -2160,6 +2723,33 @@ __metadata: languageName: node linkType: hard +"@csstools/postcss-cascade-layers@npm:^5.0.2": + version: 5.0.2 + resolution: "@csstools/postcss-cascade-layers@npm:5.0.2" + dependencies: + "@csstools/selector-specificity": ^5.0.0 + postcss-selector-parser: ^7.0.0 + peerDependencies: + postcss: ^8.4 + checksum: 597f93addd18bf0cf56b744681da6028edfba66192198f492fb37f13f87bdddce8c2da7b2dd1fa67a4ec9dfd076b55ff6d3635523df1a937767c6a12abb28b7a + languageName: node + linkType: hard + +"@csstools/postcss-color-function-display-p3-linear@npm:^1.0.1": + version: 1.0.1 + resolution: "@csstools/postcss-color-function-display-p3-linear@npm:1.0.1" + dependencies: + "@csstools/css-color-parser": ^3.1.0 + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + "@csstools/postcss-progressive-custom-properties": ^4.2.1 + "@csstools/utilities": ^2.0.0 + peerDependencies: + postcss: ^8.4 + checksum: 10b1b098d66314d287cca728c601c6905017769a31dd27488da49922937476a22eb280232e4b1df352b4f76158994dc18607cfc7b565d83346746795cb3f7844 + languageName: node + linkType: hard + "@csstools/postcss-color-function@npm:^1.1.1": version: 1.1.1 resolution: "@csstools/postcss-color-function@npm:1.1.1" @@ -2172,6 +2762,93 @@ __metadata: languageName: node linkType: hard +"@csstools/postcss-color-function@npm:^4.0.12": + version: 4.0.12 + resolution: "@csstools/postcss-color-function@npm:4.0.12" + dependencies: + "@csstools/css-color-parser": ^3.1.0 + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + "@csstools/postcss-progressive-custom-properties": ^4.2.1 + "@csstools/utilities": ^2.0.0 + peerDependencies: + postcss: ^8.4 + checksum: b13563a097966f9f670544e7f76abe8d170a59d09c5e7bd26533daf5b6bffcc74a82e694d5d970326299b5fa70c52972d9aeabe5dbd2fd90a3322668d4aa3e74 + languageName: node + linkType: hard + +"@csstools/postcss-color-mix-function@npm:^3.0.12": + version: 3.0.12 + resolution: "@csstools/postcss-color-mix-function@npm:3.0.12" + dependencies: + "@csstools/css-color-parser": ^3.1.0 + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + "@csstools/postcss-progressive-custom-properties": ^4.2.1 + "@csstools/utilities": ^2.0.0 + peerDependencies: + postcss: ^8.4 + checksum: f4ac11b913860e919fc325e817ba1dd7fa2740d6a86eb2abe92013ac8173fa4efb697f6ccffa3178526fa9ed6274ce654bf278adc86effa62dd1f5adf16e2f7c + languageName: node + linkType: hard + +"@csstools/postcss-color-mix-variadic-function-arguments@npm:^1.0.2": + version: 1.0.2 + resolution: "@csstools/postcss-color-mix-variadic-function-arguments@npm:1.0.2" + dependencies: + "@csstools/css-color-parser": ^3.1.0 + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + "@csstools/postcss-progressive-custom-properties": ^4.2.1 + "@csstools/utilities": ^2.0.0 + peerDependencies: + postcss: ^8.4 + checksum: a38642b7020589ffc684f0f4c76a2e59a8d6dc75f55036a06c9e8a109c55245234c9fb50eae6f2b97b0046591767af922d0a089a8a0c742372cf4935411f5e5c + languageName: node + linkType: hard + +"@csstools/postcss-content-alt-text@npm:^2.0.8": + version: 2.0.8 + resolution: "@csstools/postcss-content-alt-text@npm:2.0.8" + dependencies: + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + "@csstools/postcss-progressive-custom-properties": ^4.2.1 + "@csstools/utilities": ^2.0.0 + peerDependencies: + postcss: ^8.4 + checksum: a69e1daf2fddd4cfb46806a7e5888b9138d498e173b15040d27d963a3d66aaaed9097a780291229e5dafaf8292443b4adcb329d4f1a4fb7d3f04ef2edd798c12 + languageName: node + linkType: hard + +"@csstools/postcss-contrast-color-function@npm:^2.0.12": + version: 2.0.12 + resolution: "@csstools/postcss-contrast-color-function@npm:2.0.12" + dependencies: + "@csstools/css-color-parser": ^3.1.0 + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + "@csstools/postcss-progressive-custom-properties": ^4.2.1 + "@csstools/utilities": ^2.0.0 + peerDependencies: + postcss: ^8.4 + checksum: ac8fed35786d6e4c077d34b023a72278e29a5cef90ee834df273ce0197fcee9848b3d40046bfff37959f42c7cfb4f14ffac1b58a86d87a80c1759a9300db7c49 + languageName: node + linkType: hard + +"@csstools/postcss-exponential-functions@npm:^2.0.9": + version: 2.0.9 + resolution: "@csstools/postcss-exponential-functions@npm:2.0.9" + dependencies: + "@csstools/css-calc": ^2.1.4 + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + peerDependencies: + postcss: ^8.4 + checksum: 80d5847d747fc67c32ee3ba49f9c9290654fb086c58b2f13256b14124b7349dac68ba8e107f631248cef2448ca57ef18adbbbc816dd63a54ba91826345373f39 + languageName: node + linkType: hard + "@csstools/postcss-font-format-keywords@npm:^1.0.1": version: 1.0.1 resolution: "@csstools/postcss-font-format-keywords@npm:1.0.1" @@ -2183,6 +2860,46 @@ __metadata: languageName: node linkType: hard +"@csstools/postcss-font-format-keywords@npm:^4.0.0": + version: 4.0.0 + resolution: "@csstools/postcss-font-format-keywords@npm:4.0.0" + dependencies: + "@csstools/utilities": ^2.0.0 + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.4 + checksum: 63091d4748cfc5a51e3c288cd620f058a4e776ba15da6180edaee94aaad9c4e92076f575d064dabc00b28966b33dd1e59f84a6ca6a66aed59556ef92a0dfed45 + languageName: node + linkType: hard + +"@csstools/postcss-gamut-mapping@npm:^2.0.11": + version: 2.0.11 + resolution: "@csstools/postcss-gamut-mapping@npm:2.0.11" + dependencies: + "@csstools/css-color-parser": ^3.1.0 + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + peerDependencies: + postcss: ^8.4 + checksum: be4cb5a14eef78acbd9dfca7cdad0ab4e8e4a11c9e8bbb27e427bfd276fd5d3aa37bc1bf36deb040d404398989a3123bd70fc51be970c4d944cf6a18d231c1b8 + languageName: node + linkType: hard + +"@csstools/postcss-gradients-interpolation-method@npm:^5.0.12": + version: 5.0.12 + resolution: "@csstools/postcss-gradients-interpolation-method@npm:5.0.12" + dependencies: + "@csstools/css-color-parser": ^3.1.0 + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + "@csstools/postcss-progressive-custom-properties": ^4.2.1 + "@csstools/utilities": ^2.0.0 + peerDependencies: + postcss: ^8.4 + checksum: 30c7f45fc8e99a46eaf739380fdc632adb4d53702c5eaa654591bcd9ef0b40f443093933c5f92c6eaa73eaee8bd70f1e7e82c62b9623207481a4bae1075ea797 + languageName: node + linkType: hard + "@csstools/postcss-hwb-function@npm:^1.0.2": version: 1.0.2 resolution: "@csstools/postcss-hwb-function@npm:1.0.2" @@ -2194,6 +2911,21 @@ __metadata: languageName: node linkType: hard +"@csstools/postcss-hwb-function@npm:^4.0.12": + version: 4.0.12 + resolution: "@csstools/postcss-hwb-function@npm:4.0.12" + dependencies: + "@csstools/css-color-parser": ^3.1.0 + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + "@csstools/postcss-progressive-custom-properties": ^4.2.1 + "@csstools/utilities": ^2.0.0 + peerDependencies: + postcss: ^8.4 + checksum: 8e37a45cffa9458466fa9a05a0926ea1579e6b21501c59bb464282481f41a2694f45343e85d37da744a36a99a4ceb3e263aeca46ea5fcfb8a12a5558cc11efaa + languageName: node + linkType: hard + "@csstools/postcss-ic-unit@npm:^1.0.1": version: 1.0.1 resolution: "@csstools/postcss-ic-unit@npm:1.0.1" @@ -2206,6 +2938,28 @@ __metadata: languageName: node linkType: hard +"@csstools/postcss-ic-unit@npm:^4.0.4": + version: 4.0.4 + resolution: "@csstools/postcss-ic-unit@npm:4.0.4" + dependencies: + "@csstools/postcss-progressive-custom-properties": ^4.2.1 + "@csstools/utilities": ^2.0.0 + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.4 + checksum: 3bbdbba983686b9e12a5bbf36bb2ba823a6426efb9369ca415e342c37136e041929fcafacb6fa113a06a117c22785098707c91dbf306446e66618c7881553324 + languageName: node + linkType: hard + +"@csstools/postcss-initial@npm:^2.0.1": + version: 2.0.1 + resolution: "@csstools/postcss-initial@npm:2.0.1" + peerDependencies: + postcss: ^8.4 + checksum: 914e9f56faf4e69757b0c905c4808dd39b1de30d151db5817da04510b89cb19b570a405ac2ca070941a42d5ce3f48682329de5ac21ac76416a0a98fee2de2d0d + languageName: node + linkType: hard + "@csstools/postcss-is-pseudo-class@npm:^2.0.7": version: 2.0.7 resolution: "@csstools/postcss-is-pseudo-class@npm:2.0.7" @@ -2218,6 +2972,109 @@ __metadata: languageName: node linkType: hard +"@csstools/postcss-is-pseudo-class@npm:^5.0.3": + version: 5.0.3 + resolution: "@csstools/postcss-is-pseudo-class@npm:5.0.3" + dependencies: + "@csstools/selector-specificity": ^5.0.0 + postcss-selector-parser: ^7.0.0 + peerDependencies: + postcss: ^8.4 + checksum: 60474c5d651bd4dd940c2727d71b235390fb631fc347d0b29f92f7d29cf812e6c796284eeb9206441bfcd00b778068a2fadc465262a4752310b2f9abbc432973 + languageName: node + linkType: hard + +"@csstools/postcss-light-dark-function@npm:^2.0.11": + version: 2.0.11 + resolution: "@csstools/postcss-light-dark-function@npm:2.0.11" + dependencies: + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + "@csstools/postcss-progressive-custom-properties": ^4.2.1 + "@csstools/utilities": ^2.0.0 + peerDependencies: + postcss: ^8.4 + checksum: 52fa6464e31d4815557ef9bcff0a94a89549bcf1ccb4ffcc51478a5fa01815311fb2b52b96e3f671c64da8493fb50d3fc235cbfcec797f685dcccb4133dc09c4 + languageName: node + linkType: hard + +"@csstools/postcss-logical-float-and-clear@npm:^3.0.0": + version: 3.0.0 + resolution: "@csstools/postcss-logical-float-and-clear@npm:3.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 793d9a89c28d4809a83b6111d321f60947a59f119d61046e5c4023ce2caedbb221298e69b6df38995e51b763545807db7b03da47e47461622f32928fec92b65f + languageName: node + linkType: hard + +"@csstools/postcss-logical-overflow@npm:^2.0.0": + version: 2.0.0 + resolution: "@csstools/postcss-logical-overflow@npm:2.0.0" + peerDependencies: + postcss: ^8.4 + checksum: bf73ea1d7754f59773af5a7b434e9eaa2ce05c8fe7aa26a726dce8f2a42abb0f5686fbf9672d25912250226174c35f2c5737ca072d21f8b68420500b7449fe58 + languageName: node + linkType: hard + +"@csstools/postcss-logical-overscroll-behavior@npm:^2.0.0": + version: 2.0.0 + resolution: "@csstools/postcss-logical-overscroll-behavior@npm:2.0.0" + peerDependencies: + postcss: ^8.4 + checksum: bf043fdad02b9578fc2dcddb409b014a15dee65a9813ceb583237dff1caf807e18101f68bde2b0d8b685139d823114ab8deed6da3027878d11a945755824d3b1 + languageName: node + linkType: hard + +"@csstools/postcss-logical-resize@npm:^3.0.0": + version: 3.0.0 + resolution: "@csstools/postcss-logical-resize@npm:3.0.0" + dependencies: + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.4 + checksum: 3be1133a9ac27e0a0d73b19d573adc00ad78a697522eaf6c9de90260882ba8ff0904c7ab3e68379ee7724e28661c4b497cb665e258214bc8355f4a0d91021c46 + languageName: node + linkType: hard + +"@csstools/postcss-logical-viewport-units@npm:^3.0.4": + version: 3.0.4 + resolution: "@csstools/postcss-logical-viewport-units@npm:3.0.4" + dependencies: + "@csstools/css-tokenizer": ^3.0.4 + "@csstools/utilities": ^2.0.0 + peerDependencies: + postcss: ^8.4 + checksum: ddb8d9b473c55cce1c1261652d657d33d9306d80112eac578d53b05dd48a5607ea2064fcf6bc298ccc1e63143e11517d35230bad6063dae14d445530c45a81ec + languageName: node + linkType: hard + +"@csstools/postcss-media-minmax@npm:^2.0.9": + version: 2.0.9 + resolution: "@csstools/postcss-media-minmax@npm:2.0.9" + dependencies: + "@csstools/css-calc": ^2.1.4 + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + "@csstools/media-query-list-parser": ^4.0.3 + peerDependencies: + postcss: ^8.4 + checksum: 24da18a5a41daef2ea4cf7d85f459b5b425085501324a3f0546309ba13f682ab57d9aabc4e639a724cd1d91a0ead046b9ab8164adad31d89c9e39ca918f5494b + languageName: node + linkType: hard + +"@csstools/postcss-media-queries-aspect-ratio-number-values@npm:^3.0.5": + version: 3.0.5 + resolution: "@csstools/postcss-media-queries-aspect-ratio-number-values@npm:3.0.5" + dependencies: + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + "@csstools/media-query-list-parser": ^4.0.3 + peerDependencies: + postcss: ^8.4 + checksum: 5a316f59c3d422eef942d01c4007d14fad8f85ce85efce080a90d8d3eb3257dc6fcce612c5ee57cf4665993a03bc5ccb538dac8e25041242ecf74f5c348a3c5a + languageName: node + linkType: hard + "@csstools/postcss-nested-calc@npm:^1.0.0": version: 1.0.0 resolution: "@csstools/postcss-nested-calc@npm:1.0.0" @@ -2229,6 +3086,18 @@ __metadata: languageName: node linkType: hard +"@csstools/postcss-nested-calc@npm:^4.0.0": + version: 4.0.0 + resolution: "@csstools/postcss-nested-calc@npm:4.0.0" + dependencies: + "@csstools/utilities": ^2.0.0 + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.4 + checksum: f334861687d7e3a4b9c26940e767a06f07e0095cab405a5b086fca407d6f743c57b552d4504ba7d5b1700a97da3507a41bf3bc2d126a26028b79f96ea38b6af5 + languageName: node + linkType: hard + "@csstools/postcss-normalize-display-values@npm:^1.0.1": version: 1.0.1 resolution: "@csstools/postcss-normalize-display-values@npm:1.0.1" @@ -2240,6 +3109,17 @@ __metadata: languageName: node linkType: hard +"@csstools/postcss-normalize-display-values@npm:^4.0.1": + version: 4.0.1 + resolution: "@csstools/postcss-normalize-display-values@npm:4.0.1" + dependencies: + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.4 + checksum: 46138f696ddadc0777dc66e97ff3a5f5a4dfa4f25ac396590b22df66dcc46d335c19af4fb4468e35472e1379ff180c858839c3ad51e7763ba3f9d898b00fb8a1 + languageName: node + linkType: hard + "@csstools/postcss-oklab-function@npm:^1.1.1": version: 1.1.1 resolution: "@csstools/postcss-oklab-function@npm:1.1.1" @@ -2252,6 +3132,30 @@ __metadata: languageName: node linkType: hard +"@csstools/postcss-oklab-function@npm:^4.0.12": + version: 4.0.12 + resolution: "@csstools/postcss-oklab-function@npm:4.0.12" + dependencies: + "@csstools/css-color-parser": ^3.1.0 + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + "@csstools/postcss-progressive-custom-properties": ^4.2.1 + "@csstools/utilities": ^2.0.0 + peerDependencies: + postcss: ^8.4 + checksum: 28b07370bc66ef05b0311e25832bad43dd4835f4e97025162ab42b9172f8e38c5dddfcc599058c8304c654b161d6366935d5be2bae4c77e7251bedba664b8ea9 + languageName: node + linkType: hard + +"@csstools/postcss-position-area-property@npm:^1.0.0": + version: 1.0.0 + resolution: "@csstools/postcss-position-area-property@npm:1.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 50f1274b8f88d89d90494f7511c2d34736ccc6f48ce650efe85772fb1a355c98bc41b749ba6c7129de24a26536c77166a850a912b650c9c6781665ed9e85321e + languageName: node + linkType: hard + "@csstools/postcss-progressive-custom-properties@npm:^1.1.0, @csstools/postcss-progressive-custom-properties@npm:^1.3.0": version: 1.3.0 resolution: "@csstools/postcss-progressive-custom-properties@npm:1.3.0" @@ -2263,9 +3167,84 @@ __metadata: languageName: node linkType: hard -"@csstools/postcss-stepped-value-functions@npm:^1.0.1": - version: 1.0.1 - resolution: "@csstools/postcss-stepped-value-functions@npm:1.0.1" +"@csstools/postcss-progressive-custom-properties@npm:^4.2.1": + version: 4.2.1 + resolution: "@csstools/postcss-progressive-custom-properties@npm:4.2.1" + dependencies: + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.4 + checksum: c63b6b3621856c113189276c5f6bd3d77c16d9a9e64609fcdf38f46700492a79b91a25933cb60991ee525ae492fb6d2073a07a18a5391148e3eedc18b8c97013 + languageName: node + linkType: hard + +"@csstools/postcss-property-rule-prelude-list@npm:^1.0.0": + version: 1.0.0 + resolution: "@csstools/postcss-property-rule-prelude-list@npm:1.0.0" + dependencies: + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + peerDependencies: + postcss: ^8.4 + checksum: f915cef138a8a96d256a47c6c317456d3d31d516777bc3d556ad8276a2d919405cc24781c91e4c629f2bf009e79be84f38cf62ac73fe94edd7bf61d4b2c7cf93 + languageName: node + linkType: hard + +"@csstools/postcss-random-function@npm:^2.0.1": + version: 2.0.1 + resolution: "@csstools/postcss-random-function@npm:2.0.1" + dependencies: + "@csstools/css-calc": ^2.1.4 + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + peerDependencies: + postcss: ^8.4 + checksum: d421a790b11675edf493f3e48259636beca164c494ed2883042118b35674d26f04e1a46f9e89203a179e20acc2a1f5912078ec81b330a2c1a1abef7e7387e587 + languageName: node + linkType: hard + +"@csstools/postcss-relative-color-syntax@npm:^3.0.12": + version: 3.0.12 + resolution: "@csstools/postcss-relative-color-syntax@npm:3.0.12" + dependencies: + "@csstools/css-color-parser": ^3.1.0 + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + "@csstools/postcss-progressive-custom-properties": ^4.2.1 + "@csstools/utilities": ^2.0.0 + peerDependencies: + postcss: ^8.4 + checksum: 7c6b5671268c1e30e8f113305c362d567010a0164e2b573a4d878289d5e79ab390d95975375a4c1ab577a1075d244bf242a411c4ca7ecc395546664d59becc0b + languageName: node + linkType: hard + +"@csstools/postcss-scope-pseudo-class@npm:^4.0.1": + version: 4.0.1 + resolution: "@csstools/postcss-scope-pseudo-class@npm:4.0.1" + dependencies: + postcss-selector-parser: ^7.0.0 + peerDependencies: + postcss: ^8.4 + checksum: 043667ad54b3a26e619d6c16129c1f4d8f8c7cd1c52443475aa7782dbc411390c23bd2fe41ea9c6a3f280594abbcdd9d4117a3d7c27cd2a77e31e6fd11e29fc0 + languageName: node + linkType: hard + +"@csstools/postcss-sign-functions@npm:^1.1.4": + version: 1.1.4 + resolution: "@csstools/postcss-sign-functions@npm:1.1.4" + dependencies: + "@csstools/css-calc": ^2.1.4 + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + peerDependencies: + postcss: ^8.4 + checksum: 0afcb008142a0a41df51267d79cf950f4f314394dca7c041e3a0be87df56517ac5400861630a979b5bef49f01c296025106622110384039e3c8f82802d6adcde + languageName: node + linkType: hard + +"@csstools/postcss-stepped-value-functions@npm:^1.0.1": + version: 1.0.1 + resolution: "@csstools/postcss-stepped-value-functions@npm:1.0.1" dependencies: postcss-value-parser: ^4.2.0 peerDependencies: @@ -2274,6 +3253,42 @@ __metadata: languageName: node linkType: hard +"@csstools/postcss-stepped-value-functions@npm:^4.0.9": + version: 4.0.9 + resolution: "@csstools/postcss-stepped-value-functions@npm:4.0.9" + dependencies: + "@csstools/css-calc": ^2.1.4 + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + peerDependencies: + postcss: ^8.4 + checksum: 6465a883be42d4cc4a4e83be2626a1351de4bfe84a63641c53e7c39d3c0e109152489ca2d8235625cdf6726341c676b9fbbca18fe80bb5eae8d488a0e42fc5e4 + languageName: node + linkType: hard + +"@csstools/postcss-syntax-descriptor-syntax-production@npm:^1.0.1": + version: 1.0.1 + resolution: "@csstools/postcss-syntax-descriptor-syntax-production@npm:1.0.1" + dependencies: + "@csstools/css-tokenizer": ^3.0.4 + peerDependencies: + postcss: ^8.4 + checksum: d0216cf3cd0b86203c5927cb211500543dec498d6d91b393caaa1df82af7dd7570a477a9a829ab15341ef812e341a7b34193f204a18c10e571b6da8df14c2127 + languageName: node + linkType: hard + +"@csstools/postcss-system-ui-font-family@npm:^1.0.0": + version: 1.0.0 + resolution: "@csstools/postcss-system-ui-font-family@npm:1.0.0" + dependencies: + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + peerDependencies: + postcss: ^8.4 + checksum: 6e2eed873ce887e3e3cec8d36d48fb71ef68b9995275ba008b3d5538ce63704eb4c9d4b1bd8e4a9e6d605116d7658a64557abbca7858069c7e81ea386433b8f9 + languageName: node + linkType: hard + "@csstools/postcss-text-decoration-shorthand@npm:^1.0.0": version: 1.0.0 resolution: "@csstools/postcss-text-decoration-shorthand@npm:1.0.0" @@ -2285,6 +3300,18 @@ __metadata: languageName: node linkType: hard +"@csstools/postcss-text-decoration-shorthand@npm:^4.0.3": + version: 4.0.3 + resolution: "@csstools/postcss-text-decoration-shorthand@npm:4.0.3" + dependencies: + "@csstools/color-helpers": ^5.1.0 + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.4 + checksum: afc350e389bae7fdceecb3876b9be00bdbd56e5f43054f9f5de2d42b3c55a163e5ba737212030479389c9c1fca5d066f5b051da1fdf72e13191a035d2cc6f4e0 + languageName: node + linkType: hard + "@csstools/postcss-trigonometric-functions@npm:^1.0.2": version: 1.0.2 resolution: "@csstools/postcss-trigonometric-functions@npm:1.0.2" @@ -2296,6 +3323,19 @@ __metadata: languageName: node linkType: hard +"@csstools/postcss-trigonometric-functions@npm:^4.0.9": + version: 4.0.9 + resolution: "@csstools/postcss-trigonometric-functions@npm:4.0.9" + dependencies: + "@csstools/css-calc": ^2.1.4 + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + peerDependencies: + postcss: ^8.4 + checksum: c746cd986df061a87de4f2d0129aa2d2e98a2948e5005fe6fe419a9e9ec7a0f7382461847cbd3f67f8f66169bdf23a1d7f53ca6b9922ddd235ec45f2867a8825 + languageName: node + linkType: hard + "@csstools/postcss-unset-value@npm:^1.0.2": version: 1.0.2 resolution: "@csstools/postcss-unset-value@npm:1.0.2" @@ -2305,6 +3345,24 @@ __metadata: languageName: node linkType: hard +"@csstools/postcss-unset-value@npm:^4.0.0": + version: 4.0.0 + resolution: "@csstools/postcss-unset-value@npm:4.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 3d194feea11f80ba82e19733d1531546abeba0af9fe6fc105acdf10452d699661da4e1bce45101f90bcb624a30570e469cee945c5a62b9ffe1445959a0b782d1 + languageName: node + linkType: hard + +"@csstools/selector-resolve-nested@npm:^3.1.0": + version: 3.1.0 + resolution: "@csstools/selector-resolve-nested@npm:3.1.0" + peerDependencies: + postcss-selector-parser: ^7.0.0 + checksum: eaad6a6c99345cae2849a2c73daf53381fabd75851eefd830ee743e4d454d4e2930aa99c8b9e651fed92b9a8361f352c6c754abf82c576bba4953f1e59c927e9 + languageName: node + linkType: hard + "@csstools/selector-specificity@npm:^2.0.0, @csstools/selector-specificity@npm:^2.0.2": version: 2.2.0 resolution: "@csstools/selector-specificity@npm:2.2.0" @@ -2314,6 +3372,664 @@ __metadata: languageName: node linkType: hard +"@csstools/selector-specificity@npm:^5.0.0": + version: 5.0.0 + resolution: "@csstools/selector-specificity@npm:5.0.0" + peerDependencies: + postcss-selector-parser: ^7.0.0 + checksum: 8df1a01a1fa52b66c7ba0286e1c77d1faff45009876f09ddcac542a1c4bca9f34ee92a10acf056b8e7b7ac93679c1635496c6cdfd7d88dbaff2b6afd1eb823ec + languageName: node + linkType: hard + +"@csstools/utilities@npm:^2.0.0": + version: 2.0.0 + resolution: "@csstools/utilities@npm:2.0.0" + peerDependencies: + postcss: ^8.4 + checksum: c9c8d82063ec5156d56b056c9124fed95714f05d7c1a64043174b0559aa099989f17a826579f22045384defe152e32d6355b7a9660cfed96819f43fccf277941 + languageName: node + linkType: hard + +"@discoveryjs/json-ext@npm:0.5.7": + version: 0.5.7 + resolution: "@discoveryjs/json-ext@npm:0.5.7" + checksum: 2176d301cc258ea5c2324402997cf8134ebb212469c0d397591636cea8d3c02f2b3cf9fd58dcb748c7a0dade77ebdc1b10284fa63e608c033a1db52fddc69918 + languageName: node + linkType: hard + +"@docsearch/core@npm:4.6.0": + version: 4.6.0 + resolution: "@docsearch/core@npm:4.6.0" + peerDependencies: + "@types/react": ">= 16.8.0 < 20.0.0" + react: ">= 16.8.0 < 20.0.0" + react-dom: ">= 16.8.0 < 20.0.0" + peerDependenciesMeta: + "@types/react": + optional: true + react: + optional: true + react-dom: + optional: true + checksum: 1f33cac1c46d87b6d6f91ee8ad1621f8f75fa7a0f11b4a9e45b1f9003ecd2077feaf10fd5400b1dc83d0adf5b302acc27106cb68cd991f2d4f43525ab28783fd + languageName: node + linkType: hard + +"@docsearch/css@npm:4.6.0": + version: 4.6.0 + resolution: "@docsearch/css@npm:4.6.0" + checksum: d9874a4ca6e5288d0df6ea14379c2d76f3e2ffd6bbba708757bdd49dd756f5c491c65edc454fcd7cef843effeda67d3d1df55b6e97505e36a55a1c7c3695771f + languageName: node + linkType: hard + +"@docsearch/react@npm:^3.9.0 || ^4.1.0": + version: 4.6.0 + resolution: "@docsearch/react@npm:4.6.0" + dependencies: + "@algolia/autocomplete-core": 1.19.2 + "@docsearch/core": 4.6.0 + "@docsearch/css": 4.6.0 + peerDependencies: + "@types/react": ">= 16.8.0 < 20.0.0" + react: ">= 16.8.0 < 20.0.0" + react-dom: ">= 16.8.0 < 20.0.0" + search-insights: ">= 1 < 3" + peerDependenciesMeta: + "@types/react": + optional: true + react: + optional: true + react-dom: + optional: true + search-insights: + optional: true + checksum: 9292967307e7b0a3597b5ed635e27c1c71e885ce2c51556f85a8097da02e5bc53e435e2b4e2d736f60f45701e8c725c36c909064230a798adf3bc34f0f20c1f9 + languageName: node + linkType: hard + +"@docusaurus/babel@npm:3.9.2": + version: 3.9.2 + resolution: "@docusaurus/babel@npm:3.9.2" + dependencies: + "@babel/core": ^7.25.9 + "@babel/generator": ^7.25.9 + "@babel/plugin-syntax-dynamic-import": ^7.8.3 + "@babel/plugin-transform-runtime": ^7.25.9 + "@babel/preset-env": ^7.25.9 + "@babel/preset-react": ^7.25.9 + "@babel/preset-typescript": ^7.25.9 + "@babel/runtime": ^7.25.9 + "@babel/runtime-corejs3": ^7.25.9 + "@babel/traverse": ^7.25.9 + "@docusaurus/logger": 3.9.2 + "@docusaurus/utils": 3.9.2 + babel-plugin-dynamic-import-node: ^2.3.3 + fs-extra: ^11.1.1 + tslib: ^2.6.0 + checksum: eb5297a761a9cab946f21b90dc6187531cf9ddeff8a563318b7510ff1460d341241bbae82980401c6e4caca70c1ce498c2269369fa22ffbf4329b5b90efa4e01 + languageName: node + linkType: hard + +"@docusaurus/bundler@npm:3.9.2": + version: 3.9.2 + resolution: "@docusaurus/bundler@npm:3.9.2" + dependencies: + "@babel/core": ^7.25.9 + "@docusaurus/babel": 3.9.2 + "@docusaurus/cssnano-preset": 3.9.2 + "@docusaurus/logger": 3.9.2 + "@docusaurus/types": 3.9.2 + "@docusaurus/utils": 3.9.2 + babel-loader: ^9.2.1 + clean-css: ^5.3.3 + copy-webpack-plugin: ^11.0.0 + css-loader: ^6.11.0 + css-minimizer-webpack-plugin: ^5.0.1 + cssnano: ^6.1.2 + file-loader: ^6.2.0 + html-minifier-terser: ^7.2.0 + mini-css-extract-plugin: ^2.9.2 + null-loader: ^4.0.1 + postcss: ^8.5.4 + postcss-loader: ^7.3.4 + postcss-preset-env: ^10.2.1 + terser-webpack-plugin: ^5.3.9 + tslib: ^2.6.0 + url-loader: ^4.1.1 + webpack: ^5.95.0 + webpackbar: ^6.0.1 + peerDependencies: + "@docusaurus/faster": "*" + peerDependenciesMeta: + "@docusaurus/faster": + optional: true + checksum: 4ee95ff8bd61962649554e0847c0fcd0ead1bbe43cbd8d4bbb3e258a668e8789bdf4aa268619b8c41ad9e8b0da68874d1422720128fb7d603d073eb88d37bea6 + languageName: node + linkType: hard + +"@docusaurus/core@npm:3.9.2, @docusaurus/core@npm:^3.1.0": + version: 3.9.2 + resolution: "@docusaurus/core@npm:3.9.2" + dependencies: + "@docusaurus/babel": 3.9.2 + "@docusaurus/bundler": 3.9.2 + "@docusaurus/logger": 3.9.2 + "@docusaurus/mdx-loader": 3.9.2 + "@docusaurus/utils": 3.9.2 + "@docusaurus/utils-common": 3.9.2 + "@docusaurus/utils-validation": 3.9.2 + boxen: ^6.2.1 + chalk: ^4.1.2 + chokidar: ^3.5.3 + cli-table3: ^0.6.3 + combine-promises: ^1.1.0 + commander: ^5.1.0 + core-js: ^3.31.1 + detect-port: ^1.5.1 + escape-html: ^1.0.3 + eta: ^2.2.0 + eval: ^0.1.8 + execa: 5.1.1 + fs-extra: ^11.1.1 + html-tags: ^3.3.1 + html-webpack-plugin: ^5.6.0 + leven: ^3.1.0 + lodash: ^4.17.21 + open: ^8.4.0 + p-map: ^4.0.0 + prompts: ^2.4.2 + react-helmet-async: "npm:@slorber/react-helmet-async@1.3.0" + react-loadable: "npm:@docusaurus/react-loadable@6.0.0" + react-loadable-ssr-addon-v5-slorber: ^1.0.1 + react-router: ^5.3.4 + react-router-config: ^5.1.1 + react-router-dom: ^5.3.4 + semver: ^7.5.4 + serve-handler: ^6.1.6 + tinypool: ^1.0.2 + tslib: ^2.6.0 + update-notifier: ^6.0.2 + webpack: ^5.95.0 + webpack-bundle-analyzer: ^4.10.2 + webpack-dev-server: ^5.2.2 + webpack-merge: ^6.0.1 + peerDependencies: + "@mdx-js/react": ^3.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + bin: + docusaurus: bin/docusaurus.mjs + checksum: 270ef174c38f67d111273de7df9f82fdbdab974c2fdff2f316c39bf919e8ef32a82ac7471421aa046b0ee64e6e25fff875f60783735b474471155f48d0e9c0b6 + languageName: node + linkType: hard + +"@docusaurus/cssnano-preset@npm:3.9.2": + version: 3.9.2 + resolution: "@docusaurus/cssnano-preset@npm:3.9.2" + dependencies: + cssnano-preset-advanced: ^6.1.2 + postcss: ^8.5.4 + postcss-sort-media-queries: ^5.2.0 + tslib: ^2.6.0 + checksum: 21b9b787042ab00db945969c45fdd6fb489cd0811ad256e482b44db3d6846b4f9c54a5b360e76f7160736e2866602d690bbe29d3cb9b08577d7087b38720566f + languageName: node + linkType: hard + +"@docusaurus/logger@npm:3.9.2": + version: 3.9.2 + resolution: "@docusaurus/logger@npm:3.9.2" + dependencies: + chalk: ^4.1.2 + tslib: ^2.6.0 + checksum: be81769070eea5ac3ab437dcfa040e19bf4e220e727cbc5ffefce5ba788e1b26ff9d64a82e07b8b542bbe4d40e7ebdc4f5a0683a9e7c3f17e790760e89b8a06b + languageName: node + linkType: hard + +"@docusaurus/mdx-loader@npm:3.9.2": + version: 3.9.2 + resolution: "@docusaurus/mdx-loader@npm:3.9.2" + dependencies: + "@docusaurus/logger": 3.9.2 + "@docusaurus/utils": 3.9.2 + "@docusaurus/utils-validation": 3.9.2 + "@mdx-js/mdx": ^3.0.0 + "@slorber/remark-comment": ^1.0.0 + escape-html: ^1.0.3 + estree-util-value-to-estree: ^3.0.1 + file-loader: ^6.2.0 + fs-extra: ^11.1.1 + image-size: ^2.0.2 + mdast-util-mdx: ^3.0.0 + mdast-util-to-string: ^4.0.0 + rehype-raw: ^7.0.0 + remark-directive: ^3.0.0 + remark-emoji: ^4.0.0 + remark-frontmatter: ^5.0.0 + remark-gfm: ^4.0.0 + stringify-object: ^3.3.0 + tslib: ^2.6.0 + unified: ^11.0.3 + unist-util-visit: ^5.0.0 + url-loader: ^4.1.1 + vfile: ^6.0.1 + webpack: ^5.88.1 + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: d3d07ee153709645260f152fd07791ed584b74494728e3d0091183e4006e17f23ecfb47abcecb7ba83fdc56bff974c48e833b87a11b88ee3944977d2675acf56 + languageName: node + linkType: hard + +"@docusaurus/module-type-aliases@npm:3.9.2, @docusaurus/module-type-aliases@npm:^3.1.0": + version: 3.9.2 + resolution: "@docusaurus/module-type-aliases@npm:3.9.2" + dependencies: + "@docusaurus/types": 3.9.2 + "@types/history": ^4.7.11 + "@types/react": "*" + "@types/react-router-config": "*" + "@types/react-router-dom": "*" + react-helmet-async: "npm:@slorber/react-helmet-async@1.3.0" + react-loadable: "npm:@docusaurus/react-loadable@6.0.0" + peerDependencies: + react: "*" + react-dom: "*" + checksum: 3d2c1f303e0b81aea8879f440b76603a111c930d219a06500fa70276f0c39bc4d7868e8b4022b6bb10524d74c437b263ebab96304f6af49bd0cdcabe84c4f29f + languageName: node + linkType: hard + +"@docusaurus/plugin-content-blog@npm:3.9.2": + version: 3.9.2 + resolution: "@docusaurus/plugin-content-blog@npm:3.9.2" + dependencies: + "@docusaurus/core": 3.9.2 + "@docusaurus/logger": 3.9.2 + "@docusaurus/mdx-loader": 3.9.2 + "@docusaurus/theme-common": 3.9.2 + "@docusaurus/types": 3.9.2 + "@docusaurus/utils": 3.9.2 + "@docusaurus/utils-common": 3.9.2 + "@docusaurus/utils-validation": 3.9.2 + cheerio: 1.0.0-rc.12 + feed: ^4.2.2 + fs-extra: ^11.1.1 + lodash: ^4.17.21 + schema-dts: ^1.1.2 + srcset: ^4.0.0 + tslib: ^2.6.0 + unist-util-visit: ^5.0.0 + utility-types: ^3.10.0 + webpack: ^5.88.1 + peerDependencies: + "@docusaurus/plugin-content-docs": "*" + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: 10eab3d9d09d1c45c6a0793a98757b3235d557a0e4c9e184c9a06e0ab7281fd6a691364650b257b385dd8ff38c95dc0707a70b672c9b36cb10e35012ff352328 + languageName: node + linkType: hard + +"@docusaurus/plugin-content-docs@npm:3.9.2": + version: 3.9.2 + resolution: "@docusaurus/plugin-content-docs@npm:3.9.2" + dependencies: + "@docusaurus/core": 3.9.2 + "@docusaurus/logger": 3.9.2 + "@docusaurus/mdx-loader": 3.9.2 + "@docusaurus/module-type-aliases": 3.9.2 + "@docusaurus/theme-common": 3.9.2 + "@docusaurus/types": 3.9.2 + "@docusaurus/utils": 3.9.2 + "@docusaurus/utils-common": 3.9.2 + "@docusaurus/utils-validation": 3.9.2 + "@types/react-router-config": ^5.0.7 + combine-promises: ^1.1.0 + fs-extra: ^11.1.1 + js-yaml: ^4.1.0 + lodash: ^4.17.21 + schema-dts: ^1.1.2 + tslib: ^2.6.0 + utility-types: ^3.10.0 + webpack: ^5.88.1 + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: cc927d4e3711c71221cf68e97bc86c10b762a10f3589b252a865a8e409e1a37eda3092573aa1bd9f1ab9aa71a00c000a09079b1ac33aeff9adb6a90afb65fa59 + languageName: node + linkType: hard + +"@docusaurus/plugin-content-pages@npm:3.9.2": + version: 3.9.2 + resolution: "@docusaurus/plugin-content-pages@npm:3.9.2" + dependencies: + "@docusaurus/core": 3.9.2 + "@docusaurus/mdx-loader": 3.9.2 + "@docusaurus/types": 3.9.2 + "@docusaurus/utils": 3.9.2 + "@docusaurus/utils-validation": 3.9.2 + fs-extra: ^11.1.1 + tslib: ^2.6.0 + webpack: ^5.88.1 + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: cf581f07f6260f5cec106b4641f399582b94b21ee66cb07096ebc5924caf9862eb9bfa2a57b20f05d920917cd6838d58dc3667c07ca3f9655a11fb168594b93e + languageName: node + linkType: hard + +"@docusaurus/plugin-css-cascade-layers@npm:3.9.2": + version: 3.9.2 + resolution: "@docusaurus/plugin-css-cascade-layers@npm:3.9.2" + dependencies: + "@docusaurus/core": 3.9.2 + "@docusaurus/types": 3.9.2 + "@docusaurus/utils": 3.9.2 + "@docusaurus/utils-validation": 3.9.2 + tslib: ^2.6.0 + checksum: 350aa4826eaa9b26d504784ffa14886594926066dcd1ff363b104a997873210c30c78b98e05de365def527f5ae275343b19e5d2ee49589a159bd68c81bf0f12b + languageName: node + linkType: hard + +"@docusaurus/plugin-debug@npm:3.9.2": + version: 3.9.2 + resolution: "@docusaurus/plugin-debug@npm:3.9.2" + dependencies: + "@docusaurus/core": 3.9.2 + "@docusaurus/types": 3.9.2 + "@docusaurus/utils": 3.9.2 + fs-extra: ^11.1.1 + react-json-view-lite: ^2.3.0 + tslib: ^2.6.0 + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: 8974d17143f3b379c977441011f6c9daa8d38eb484c33726b9e9a63012553e66847a1a18e7e86ed52bc5321d2833ee8e934a1619afcdd669b255089ffd23a506 + languageName: node + linkType: hard + +"@docusaurus/plugin-google-analytics@npm:3.9.2": + version: 3.9.2 + resolution: "@docusaurus/plugin-google-analytics@npm:3.9.2" + dependencies: + "@docusaurus/core": 3.9.2 + "@docusaurus/types": 3.9.2 + "@docusaurus/utils-validation": 3.9.2 + tslib: ^2.6.0 + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: 026ffe26b4e47adf509f3de79a9a4b095e0374e4db0ce73041f9d28933df1e7697069bce7a0be1744eeca2b2d5ed057f023f4f2e98aff838b33cc2c2d1eed882 + languageName: node + linkType: hard + +"@docusaurus/plugin-google-gtag@npm:3.9.2": + version: 3.9.2 + resolution: "@docusaurus/plugin-google-gtag@npm:3.9.2" + dependencies: + "@docusaurus/core": 3.9.2 + "@docusaurus/types": 3.9.2 + "@docusaurus/utils-validation": 3.9.2 + "@types/gtag.js": ^0.0.12 + tslib: ^2.6.0 + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: ee596c5a1d1a71d947c390274326b46a9aeb56c3d0c0c0b672629e890e783f6f6947505dc66ee0abe4d70fe61f743ff9df0a4b4cdc4fe3994eefbb1a4386769b + languageName: node + linkType: hard + +"@docusaurus/plugin-google-tag-manager@npm:3.9.2": + version: 3.9.2 + resolution: "@docusaurus/plugin-google-tag-manager@npm:3.9.2" + dependencies: + "@docusaurus/core": 3.9.2 + "@docusaurus/types": 3.9.2 + "@docusaurus/utils-validation": 3.9.2 + tslib: ^2.6.0 + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: 0c4ee07b5ee2cdf252b53aa52b54f42ae591441df5e289e2a1614bcabe1852f973ec65a1086c7682f7e5a5e65a50c0597ed9c393505c2902f1a52569798ef6c0 + languageName: node + linkType: hard + +"@docusaurus/plugin-sitemap@npm:3.9.2": + version: 3.9.2 + resolution: "@docusaurus/plugin-sitemap@npm:3.9.2" + dependencies: + "@docusaurus/core": 3.9.2 + "@docusaurus/logger": 3.9.2 + "@docusaurus/types": 3.9.2 + "@docusaurus/utils": 3.9.2 + "@docusaurus/utils-common": 3.9.2 + "@docusaurus/utils-validation": 3.9.2 + fs-extra: ^11.1.1 + sitemap: ^7.1.1 + tslib: ^2.6.0 + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: 0f72e1868ce2fcd2f636a1a7949145f31a8d3ec68061dbb3d62689ea77f00a2a4a5f3d8578dac2f2178e3b96240a15c1d89bf74d2c43d6fb3a14b183cd97c174 + languageName: node + linkType: hard + +"@docusaurus/plugin-svgr@npm:3.9.2": + version: 3.9.2 + resolution: "@docusaurus/plugin-svgr@npm:3.9.2" + dependencies: + "@docusaurus/core": 3.9.2 + "@docusaurus/types": 3.9.2 + "@docusaurus/utils": 3.9.2 + "@docusaurus/utils-validation": 3.9.2 + "@svgr/core": 8.1.0 + "@svgr/webpack": ^8.1.0 + tslib: ^2.6.0 + webpack: ^5.88.1 + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: 941dab80101e5d65a3c9a063d30b713297173bc117cea7638f58abe69d8c9051baaa5f912359427acfc04fb3b97f26f3f86e9ecbdd8d30dec386834bb3f6c9c8 + languageName: node + linkType: hard + +"@docusaurus/preset-classic@npm:^3.1.0": + version: 3.9.2 + resolution: "@docusaurus/preset-classic@npm:3.9.2" + dependencies: + "@docusaurus/core": 3.9.2 + "@docusaurus/plugin-content-blog": 3.9.2 + "@docusaurus/plugin-content-docs": 3.9.2 + "@docusaurus/plugin-content-pages": 3.9.2 + "@docusaurus/plugin-css-cascade-layers": 3.9.2 + "@docusaurus/plugin-debug": 3.9.2 + "@docusaurus/plugin-google-analytics": 3.9.2 + "@docusaurus/plugin-google-gtag": 3.9.2 + "@docusaurus/plugin-google-tag-manager": 3.9.2 + "@docusaurus/plugin-sitemap": 3.9.2 + "@docusaurus/plugin-svgr": 3.9.2 + "@docusaurus/theme-classic": 3.9.2 + "@docusaurus/theme-common": 3.9.2 + "@docusaurus/theme-search-algolia": 3.9.2 + "@docusaurus/types": 3.9.2 + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: ae8328253111429e9ca219273d5ae8c39f26a98c2422b25a8d233e3a0f2737e453dd1dbcc29e4c9a601b936d0217b3e91dce218d12f9f33793ae3120ed629c1c + languageName: node + linkType: hard + +"@docusaurus/theme-classic@npm:3.9.2": + version: 3.9.2 + resolution: "@docusaurus/theme-classic@npm:3.9.2" + dependencies: + "@docusaurus/core": 3.9.2 + "@docusaurus/logger": 3.9.2 + "@docusaurus/mdx-loader": 3.9.2 + "@docusaurus/module-type-aliases": 3.9.2 + "@docusaurus/plugin-content-blog": 3.9.2 + "@docusaurus/plugin-content-docs": 3.9.2 + "@docusaurus/plugin-content-pages": 3.9.2 + "@docusaurus/theme-common": 3.9.2 + "@docusaurus/theme-translations": 3.9.2 + "@docusaurus/types": 3.9.2 + "@docusaurus/utils": 3.9.2 + "@docusaurus/utils-common": 3.9.2 + "@docusaurus/utils-validation": 3.9.2 + "@mdx-js/react": ^3.0.0 + clsx: ^2.0.0 + infima: 0.2.0-alpha.45 + lodash: ^4.17.21 + nprogress: ^0.2.0 + postcss: ^8.5.4 + prism-react-renderer: ^2.3.0 + prismjs: ^1.29.0 + react-router-dom: ^5.3.4 + rtlcss: ^4.1.0 + tslib: ^2.6.0 + utility-types: ^3.10.0 + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: 19d0e89fa5d17bfde05642466137770baafe1528cad9540e55ba7969694fc456cdafdde175591a2e8d389cd1fb71eb13d2034b7bc6e4aa724d5531d224426413 + languageName: node + linkType: hard + +"@docusaurus/theme-common@npm:3.9.2": + version: 3.9.2 + resolution: "@docusaurus/theme-common@npm:3.9.2" + dependencies: + "@docusaurus/mdx-loader": 3.9.2 + "@docusaurus/module-type-aliases": 3.9.2 + "@docusaurus/utils": 3.9.2 + "@docusaurus/utils-common": 3.9.2 + "@types/history": ^4.7.11 + "@types/react": "*" + "@types/react-router-config": "*" + clsx: ^2.0.0 + parse-numeric-range: ^1.3.0 + prism-react-renderer: ^2.3.0 + tslib: ^2.6.0 + utility-types: ^3.10.0 + peerDependencies: + "@docusaurus/plugin-content-docs": "*" + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: 9d5e2ef0f895a3c8d5ebbe1aca620fcdde91166397084654a6288957ba69ff3b3bfeb0c4518ff64cd5fb2d7c245dd852cb22516507237ad8f6d13ed297ff8d71 + languageName: node + linkType: hard + +"@docusaurus/theme-search-algolia@npm:3.9.2": + version: 3.9.2 + resolution: "@docusaurus/theme-search-algolia@npm:3.9.2" + dependencies: + "@docsearch/react": ^3.9.0 || ^4.1.0 + "@docusaurus/core": 3.9.2 + "@docusaurus/logger": 3.9.2 + "@docusaurus/plugin-content-docs": 3.9.2 + "@docusaurus/theme-common": 3.9.2 + "@docusaurus/theme-translations": 3.9.2 + "@docusaurus/utils": 3.9.2 + "@docusaurus/utils-validation": 3.9.2 + algoliasearch: ^5.37.0 + algoliasearch-helper: ^3.26.0 + clsx: ^2.0.0 + eta: ^2.2.0 + fs-extra: ^11.1.1 + lodash: ^4.17.21 + tslib: ^2.6.0 + utility-types: ^3.10.0 + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: 0dc6affcb778ba525c14f944e34fa6ff68ac753221f7a0f832d51f7e37d1ffbd7084f0d164ede57759e5160b6c071387ca4f517b12f91b6f0d3a13aa57e14393 + languageName: node + linkType: hard + +"@docusaurus/theme-translations@npm:3.9.2": + version: 3.9.2 + resolution: "@docusaurus/theme-translations@npm:3.9.2" + dependencies: + fs-extra: ^11.1.1 + tslib: ^2.6.0 + checksum: 166e534cc2533a369ac29384ddfc728402739f55d6ea8e6c498e0707e7c02c3232a8f1a7f28f3f1fd1abd901f41b6731ee5d603c689a0c4f6eac30b94c07e667 + languageName: node + linkType: hard + +"@docusaurus/types@npm:3.9.2, @docusaurus/types@npm:^3.1.0": + version: 3.9.2 + resolution: "@docusaurus/types@npm:3.9.2" + dependencies: + "@mdx-js/mdx": ^3.0.0 + "@types/history": ^4.7.11 + "@types/mdast": ^4.0.2 + "@types/react": "*" + commander: ^5.1.0 + joi: ^17.9.2 + react-helmet-async: "npm:@slorber/react-helmet-async@1.3.0" + utility-types: ^3.10.0 + webpack: ^5.95.0 + webpack-merge: ^5.9.0 + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: 6f856de4dc482e4d358fda9fe4e8913561bb1f3cdafc12995cb0773b945cacedcde262c5a36bafdde690acdfb2c2cb14fd58290f6fbe9720189ff10f37b18962 + languageName: node + linkType: hard + +"@docusaurus/utils-common@npm:3.9.2": + version: 3.9.2 + resolution: "@docusaurus/utils-common@npm:3.9.2" + dependencies: + "@docusaurus/types": 3.9.2 + tslib: ^2.6.0 + checksum: 77e01da05ebbf202343b3131ffaba7132c764ccc0ab48dd4421535c75a59e2d4a1dcaf8471cde257b5394528ada52f79da6398f6f2eb9fde79904be736f19275 + languageName: node + linkType: hard + +"@docusaurus/utils-validation@npm:3.9.2": + version: 3.9.2 + resolution: "@docusaurus/utils-validation@npm:3.9.2" + dependencies: + "@docusaurus/logger": 3.9.2 + "@docusaurus/utils": 3.9.2 + "@docusaurus/utils-common": 3.9.2 + fs-extra: ^11.2.0 + joi: ^17.9.2 + js-yaml: ^4.1.0 + lodash: ^4.17.21 + tslib: ^2.6.0 + checksum: 17599a47be486c62c7867e57a37afaf89155c9852bfaff7159191983b111176b222ef50bfb60848e7465d2dfd65f90bc9fd6f7015838767fab3126afb677c2d9 + languageName: node + linkType: hard + +"@docusaurus/utils@npm:3.9.2": + version: 3.9.2 + resolution: "@docusaurus/utils@npm:3.9.2" + dependencies: + "@docusaurus/logger": 3.9.2 + "@docusaurus/types": 3.9.2 + "@docusaurus/utils-common": 3.9.2 + escape-string-regexp: ^4.0.0 + execa: 5.1.1 + file-loader: ^6.2.0 + fs-extra: ^11.1.1 + github-slugger: ^1.5.0 + globby: ^11.1.0 + gray-matter: ^4.0.3 + jiti: ^1.20.0 + js-yaml: ^4.1.0 + lodash: ^4.17.21 + micromatch: ^4.0.5 + p-queue: ^6.6.2 + prompts: ^2.4.2 + resolve-pathname: ^3.0.0 + tslib: ^2.6.0 + url-loader: ^4.1.1 + utility-types: ^3.10.0 + webpack: ^5.88.1 + checksum: c88de8ea7835da1ea4114ff1aa9e97546565d7f20dcad3b3e9ef3663f536468a8a4f36431037ca60e7ac019b069adea40d1ef839bdaaf0daea661bd2fa954045 + languageName: node + linkType: hard + "@emotion/babel-plugin@npm:^11.13.5": version: 11.13.5 resolution: "@emotion/babel-plugin@npm:11.13.5" @@ -3229,6 +4945,22 @@ __metadata: languageName: node linkType: hard +"@hapi/hoek@npm:^9.0.0, @hapi/hoek@npm:^9.3.0": + version: 9.3.0 + resolution: "@hapi/hoek@npm:9.3.0" + checksum: 4771c7a776242c3c022b168046af4e324d116a9d2e1d60631ee64f474c6e38d1bb07092d898bf95c7bc5d334c5582798a1456321b2e53ca817d4e7c88bc25b43 + languageName: node + linkType: hard + +"@hapi/topo@npm:^5.1.0": + version: 5.1.0 + resolution: "@hapi/topo@npm:5.1.0" + dependencies: + "@hapi/hoek": ^9.0.0 + checksum: 604dfd5dde76d5c334bd03f9001fce69c7ce529883acf92da96f4fe7e51221bf5e5110e964caca287a6a616ba027c071748ab636ff178ad750547fba611d6014 + languageName: node + linkType: hard + "@hello-pangea/dnd@npm:^17.0.0": version: 17.0.0 resolution: "@hello-pangea/dnd@npm:17.0.0" @@ -3742,7 +5474,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25, @jridgewell/trace-mapping@npm:^0.3.28": +"@jridgewell/trace-mapping@npm:^0.3.18, @jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25, @jridgewell/trace-mapping@npm:^0.3.28": version: 0.3.31 resolution: "@jridgewell/trace-mapping@npm:0.3.31" dependencies: @@ -3752,6 +5484,246 @@ __metadata: languageName: node linkType: hard +"@jsonjoy.com/base64@npm:17.67.0": + version: 17.67.0 + resolution: "@jsonjoy.com/base64@npm:17.67.0" + peerDependencies: + tslib: 2 + checksum: e5c5b0dd3bd57fe31799ceacf516fd1ef9cb02def5d6fd54fd6afc06387b8220d399aaa65cf71dcb303ed45f32dff950d56e9af6d0dcaf6b676058e2594a62ec + languageName: node + linkType: hard + +"@jsonjoy.com/base64@npm:^1.1.2": + version: 1.1.2 + resolution: "@jsonjoy.com/base64@npm:1.1.2" + peerDependencies: + tslib: 2 + checksum: 00dbf9cbc6ecb3af0e58288a305cc4ee3dfca9efa24443d98061756e8f6de4d6d2d3764bdfde07f2b03e6ce56db27c8a59b490bd134bf3d8122b4c6b394c7010 + languageName: node + linkType: hard + +"@jsonjoy.com/buffers@npm:17.67.0, @jsonjoy.com/buffers@npm:^17.65.0": + version: 17.67.0 + resolution: "@jsonjoy.com/buffers@npm:17.67.0" + peerDependencies: + tslib: 2 + checksum: 68b0f0268c79f79a2c8e4aefd02626471f0df7e77a96d186001bdfc2ed3a0855a111aaef943e688712cf677bb265b182b6ec5abe4dea26c32dc0322f988d5f8d + languageName: node + linkType: hard + +"@jsonjoy.com/buffers@npm:^1.0.0, @jsonjoy.com/buffers@npm:^1.2.0": + version: 1.2.1 + resolution: "@jsonjoy.com/buffers@npm:1.2.1" + peerDependencies: + tslib: 2 + checksum: 5de11264a7ffe62e5ee3e4f9328bb01cb18dd9d4b977ce1a98e134860c630ae801cf535b78f7a618c33955061d49f0b09699eb77b10e0e45b942f7bb48a19791 + languageName: node + linkType: hard + +"@jsonjoy.com/codegen@npm:17.67.0": + version: 17.67.0 + resolution: "@jsonjoy.com/codegen@npm:17.67.0" + peerDependencies: + tslib: 2 + checksum: 11195d6247c21e429ccdfa9cfd4b15bfea6fdc059e5beb25ca9d129a79fcb9a636d6d10ad3845dbaa480a318323496be2fe3cfcd5a217e2b577012b93a78a46a + languageName: node + linkType: hard + +"@jsonjoy.com/codegen@npm:^1.0.0": + version: 1.0.0 + resolution: "@jsonjoy.com/codegen@npm:1.0.0" + peerDependencies: + tslib: 2 + checksum: 77383ed703dacc0ee35783589f3289e464d9fd047675f2f628b4d8a567c2b9c87f0121f4445203d51645b5777d24c3b50ed7e12525f4064a0614caae81b1dc2e + languageName: node + linkType: hard + +"@jsonjoy.com/fs-core@npm:4.56.10": + version: 4.56.10 + resolution: "@jsonjoy.com/fs-core@npm:4.56.10" + dependencies: + "@jsonjoy.com/fs-node-builtins": 4.56.10 + "@jsonjoy.com/fs-node-utils": 4.56.10 + thingies: ^2.5.0 + peerDependencies: + tslib: 2 + checksum: d6bf86ec80ad33753b832735e5817b262d9b4667c687eed659bcebdaf19d0c2239b9d6f08b8fb366c5b28083a00fffb9840a7d552e2567d818c0fa886d20e24b + languageName: node + linkType: hard + +"@jsonjoy.com/fs-fsa@npm:4.56.10": + version: 4.56.10 + resolution: "@jsonjoy.com/fs-fsa@npm:4.56.10" + dependencies: + "@jsonjoy.com/fs-core": 4.56.10 + "@jsonjoy.com/fs-node-builtins": 4.56.10 + "@jsonjoy.com/fs-node-utils": 4.56.10 + thingies: ^2.5.0 + peerDependencies: + tslib: 2 + checksum: f3eecd70f8151074b16b4c3e04efac685d4fe19b19c49bbe798f99f501cc9cd31c3a18a7cc3fd9060b42ea7ed5d37452eab6554c992ed560747a4e8b12984ffe + languageName: node + linkType: hard + +"@jsonjoy.com/fs-node-builtins@npm:4.56.10": + version: 4.56.10 + resolution: "@jsonjoy.com/fs-node-builtins@npm:4.56.10" + peerDependencies: + tslib: 2 + checksum: b383f3f0c0c66a5ba22dd922ca21c3a08d37060c469f62e50f74b3f99f874a11e4b0099ba92da53c818cdb31b39068393466374858cdcbaea0fd17904d2c3dd6 + languageName: node + linkType: hard + +"@jsonjoy.com/fs-node-to-fsa@npm:4.56.10": + version: 4.56.10 + resolution: "@jsonjoy.com/fs-node-to-fsa@npm:4.56.10" + dependencies: + "@jsonjoy.com/fs-fsa": 4.56.10 + "@jsonjoy.com/fs-node-builtins": 4.56.10 + "@jsonjoy.com/fs-node-utils": 4.56.10 + peerDependencies: + tslib: 2 + checksum: 1d798ddc5a2b36e1a173b73543a435bcf282ec195f0b78cc500b73ecd521dbaba250855a6883d2406d264b95582e8fca4b1e4094d190fc64252408c399c666e7 + languageName: node + linkType: hard + +"@jsonjoy.com/fs-node-utils@npm:4.56.10": + version: 4.56.10 + resolution: "@jsonjoy.com/fs-node-utils@npm:4.56.10" + dependencies: + "@jsonjoy.com/fs-node-builtins": 4.56.10 + peerDependencies: + tslib: 2 + checksum: 9beb585652e7699c9a8526737e5a20418586beb3b07b57930cd34ea2eef0acc2179c9987f024b30575aee9eaed079dabf236757a8abb60f7dd3f6cd25708c494 + languageName: node + linkType: hard + +"@jsonjoy.com/fs-node@npm:4.56.10": + version: 4.56.10 + resolution: "@jsonjoy.com/fs-node@npm:4.56.10" + dependencies: + "@jsonjoy.com/fs-core": 4.56.10 + "@jsonjoy.com/fs-node-builtins": 4.56.10 + "@jsonjoy.com/fs-node-utils": 4.56.10 + "@jsonjoy.com/fs-print": 4.56.10 + "@jsonjoy.com/fs-snapshot": 4.56.10 + glob-to-regex.js: ^1.0.0 + thingies: ^2.5.0 + peerDependencies: + tslib: 2 + checksum: 898ecdb4a3ca782de39c5a5985710f031da9d17eb9117ef07d7e47ef91a5fbacec4ecefb6978026201d5638eed9a13e65d7b888ba20d418346a7924227c8dc57 + languageName: node + linkType: hard + +"@jsonjoy.com/fs-print@npm:4.56.10": + version: 4.56.10 + resolution: "@jsonjoy.com/fs-print@npm:4.56.10" + dependencies: + "@jsonjoy.com/fs-node-utils": 4.56.10 + tree-dump: ^1.1.0 + peerDependencies: + tslib: 2 + checksum: 9eff4f179624f9bee799e2a7abcc311a512284fae2c149cd85378604e407bba613d95af065275caf37e0a16a015a040cb4a99cec8c51ac6d393bcf9c343c0d8e + languageName: node + linkType: hard + +"@jsonjoy.com/fs-snapshot@npm:4.56.10": + version: 4.56.10 + resolution: "@jsonjoy.com/fs-snapshot@npm:4.56.10" + dependencies: + "@jsonjoy.com/buffers": ^17.65.0 + "@jsonjoy.com/fs-node-utils": 4.56.10 + "@jsonjoy.com/json-pack": ^17.65.0 + "@jsonjoy.com/util": ^17.65.0 + peerDependencies: + tslib: 2 + checksum: 8abbc8171ab0b30eca5b1f06f1a5fcaf1d04ca342fd9fca497571cbfd4a05c444773945222f2b4cda952931d6703dff743ee554c78ca447d2051698f74c6595c + languageName: node + linkType: hard + +"@jsonjoy.com/json-pack@npm:^1.11.0": + version: 1.21.0 + resolution: "@jsonjoy.com/json-pack@npm:1.21.0" + dependencies: + "@jsonjoy.com/base64": ^1.1.2 + "@jsonjoy.com/buffers": ^1.2.0 + "@jsonjoy.com/codegen": ^1.0.0 + "@jsonjoy.com/json-pointer": ^1.0.2 + "@jsonjoy.com/util": ^1.9.0 + hyperdyperid: ^1.2.0 + thingies: ^2.5.0 + tree-dump: ^1.1.0 + peerDependencies: + tslib: 2 + checksum: 653b02514bd4ca5e57f72d1fe1b57181767001a4b2615f35135085309cc91fd47f7421c17a465becc76d986871831d4a1cb68506720547e7e7fc0822d6bc5092 + languageName: node + linkType: hard + +"@jsonjoy.com/json-pack@npm:^17.65.0": + version: 17.67.0 + resolution: "@jsonjoy.com/json-pack@npm:17.67.0" + dependencies: + "@jsonjoy.com/base64": 17.67.0 + "@jsonjoy.com/buffers": 17.67.0 + "@jsonjoy.com/codegen": 17.67.0 + "@jsonjoy.com/json-pointer": 17.67.0 + "@jsonjoy.com/util": 17.67.0 + hyperdyperid: ^1.2.0 + thingies: ^2.5.0 + tree-dump: ^1.1.0 + peerDependencies: + tslib: 2 + checksum: f04ae650b26aca75e2b1879ea9a6026ef66c5947882b22ddc03f1bc5ff6bb2b643cd024b2ab3e863d4036bbe3d67afbfbd02309dc32c5fe1b5fc9efce1baf659 + languageName: node + linkType: hard + +"@jsonjoy.com/json-pointer@npm:17.67.0": + version: 17.67.0 + resolution: "@jsonjoy.com/json-pointer@npm:17.67.0" + dependencies: + "@jsonjoy.com/util": 17.67.0 + peerDependencies: + tslib: 2 + checksum: 6ff4fe4926be6e6dcc570075ca0b79efc017ca77145acb4790123135d307efa27082638007ff329ce8fab399702c3e2af2b7fa071aca76f83be50fb95131e2c7 + languageName: node + linkType: hard + +"@jsonjoy.com/json-pointer@npm:^1.0.2": + version: 1.0.2 + resolution: "@jsonjoy.com/json-pointer@npm:1.0.2" + dependencies: + "@jsonjoy.com/codegen": ^1.0.0 + "@jsonjoy.com/util": ^1.9.0 + peerDependencies: + tslib: 2 + checksum: 93b45eb2e5ea3864778dab45c9fd2313cd9fb0fc9fa9a6401c8dea0365e44551fa8debbf3d0efb8b5131c0fde689f4509248b3e2ba12852a8c75739028ec3c1b + languageName: node + linkType: hard + +"@jsonjoy.com/util@npm:17.67.0, @jsonjoy.com/util@npm:^17.65.0": + version: 17.67.0 + resolution: "@jsonjoy.com/util@npm:17.67.0" + dependencies: + "@jsonjoy.com/buffers": 17.67.0 + "@jsonjoy.com/codegen": 17.67.0 + peerDependencies: + tslib: 2 + checksum: 945c5e7e889ad4b6c6d3b5fc7a3396e7b1b9db9b2d065a5231c29ffef03c202f4c8e2ac51f6024faba2ad348620f94f3c606c8cae8f5ba4c23cba05b409000f6 + languageName: node + linkType: hard + +"@jsonjoy.com/util@npm:^1.9.0": + version: 1.9.0 + resolution: "@jsonjoy.com/util@npm:1.9.0" + dependencies: + "@jsonjoy.com/buffers": ^1.0.0 + "@jsonjoy.com/codegen": ^1.0.0 + peerDependencies: + tslib: 2 + checksum: a22c49af0736cede94c24ad8da7230f42697eb5c4a6016450d5bf1cbcb51cd5b45a08989e7ec4cad1cc47718cb5b26e0ba583189f238d095eae4b15cbbe8c9e7 + languageName: node + linkType: hard + "@kurkle/color@npm:^0.3.0": version: 0.3.4 resolution: "@kurkle/color@npm:0.3.4" @@ -3766,6 +5738,51 @@ __metadata: languageName: node linkType: hard +"@mdx-js/mdx@npm:^3.0.0": + version: 3.1.1 + resolution: "@mdx-js/mdx@npm:3.1.1" + dependencies: + "@types/estree": ^1.0.0 + "@types/estree-jsx": ^1.0.0 + "@types/hast": ^3.0.0 + "@types/mdx": ^2.0.0 + acorn: ^8.0.0 + collapse-white-space: ^2.0.0 + devlop: ^1.0.0 + estree-util-is-identifier-name: ^3.0.0 + estree-util-scope: ^1.0.0 + estree-walker: ^3.0.0 + hast-util-to-jsx-runtime: ^2.0.0 + markdown-extensions: ^2.0.0 + recma-build-jsx: ^1.0.0 + recma-jsx: ^1.0.0 + recma-stringify: ^1.0.0 + rehype-recma: ^1.0.0 + remark-mdx: ^3.0.0 + remark-parse: ^11.0.0 + remark-rehype: ^11.0.0 + source-map: ^0.7.0 + unified: ^11.0.0 + unist-util-position-from-estree: ^2.0.0 + unist-util-stringify-position: ^4.0.0 + unist-util-visit: ^5.0.0 + vfile: ^6.0.0 + checksum: 6e624abc177345b80e1fedd0e899e06ceb2e73dfba7b4a5ac59e415a3f905048818dbe6e89c46e20cafcb20ef53ea6901193fbd5d59fa661680d81b837b6d7df + languageName: node + linkType: hard + +"@mdx-js/react@npm:^3.0.0": + version: 3.1.1 + resolution: "@mdx-js/react@npm:3.1.1" + dependencies: + "@types/mdx": ^2.0.0 + peerDependencies: + "@types/react": ">=16" + react: ">=16" + checksum: 7e1742c530dd4b5b586f9ccbc8451062b9a1b4c3c8dd00537aa910b34c7404e4120d50dbd0a19f1697ae8e600d9e5848e29fad846d2975b7c5c7d8d2bd798c83 + languageName: node + linkType: hard + "@microsoft/clarity@npm:^1.0.0": version: 1.0.2 resolution: "@microsoft/clarity@npm:1.0.2" @@ -4161,6 +6178,13 @@ __metadata: languageName: node linkType: hard +"@noble/hashes@npm:1.4.0": + version: 1.4.0 + resolution: "@noble/hashes@npm:1.4.0" + checksum: 8ba816ae26c90764b8c42493eea383716396096c5f7ba6bea559993194f49d80a73c081f315f4c367e51bd2d5891700bcdfa816b421d24ab45b41cb03e4f3342 + languageName: node + linkType: hard + "@noble/hashes@npm:^1.1.5": version: 1.8.0 resolution: "@noble/hashes@npm:1.8.0" @@ -4412,6 +6436,151 @@ __metadata: languageName: node linkType: hard +"@peculiar/asn1-cms@npm:^2.6.0, @peculiar/asn1-cms@npm:^2.6.1": + version: 2.6.1 + resolution: "@peculiar/asn1-cms@npm:2.6.1" + dependencies: + "@peculiar/asn1-schema": ^2.6.0 + "@peculiar/asn1-x509": ^2.6.1 + "@peculiar/asn1-x509-attr": ^2.6.1 + asn1js: ^3.0.6 + tslib: ^2.8.1 + checksum: e5fa34cdb8a0201c6082790f66e1a9bb4dc5648c7acf32e09b84cbe254ce0ed91704649c94c56a14f3c2499559709bb4e6f8394e2742e7c2f3a7fb715d1cd7fd + languageName: node + linkType: hard + +"@peculiar/asn1-csr@npm:^2.6.0": + version: 2.6.1 + resolution: "@peculiar/asn1-csr@npm:2.6.1" + dependencies: + "@peculiar/asn1-schema": ^2.6.0 + "@peculiar/asn1-x509": ^2.6.1 + asn1js: ^3.0.6 + tslib: ^2.8.1 + checksum: ec0108ad630c2099a1853dd0749c38d883564bec2367bd7f2c3653ebcce68bc3685bd55c1344a4aa103d5bf8e3b3eaef7eb3a038e6a5eba1bd4b4ce1f8d769e3 + languageName: node + linkType: hard + +"@peculiar/asn1-ecc@npm:^2.6.0": + version: 2.6.1 + resolution: "@peculiar/asn1-ecc@npm:2.6.1" + dependencies: + "@peculiar/asn1-schema": ^2.6.0 + "@peculiar/asn1-x509": ^2.6.1 + asn1js: ^3.0.6 + tslib: ^2.8.1 + checksum: d66ac931529a1b6c2a5a4942157a934a1f8ac5261bbe7c012d14c9ef98765b335f7de41ba1c1de3e4840b21659d164dc3f01aa676fc932951f92925487be26fd + languageName: node + linkType: hard + +"@peculiar/asn1-pfx@npm:^2.6.1": + version: 2.6.1 + resolution: "@peculiar/asn1-pfx@npm:2.6.1" + dependencies: + "@peculiar/asn1-cms": ^2.6.1 + "@peculiar/asn1-pkcs8": ^2.6.1 + "@peculiar/asn1-rsa": ^2.6.1 + "@peculiar/asn1-schema": ^2.6.0 + asn1js: ^3.0.6 + tslib: ^2.8.1 + checksum: 2fddb69bccf212ff3d219c5490dc513da06443f6cec112a2bf10d17338f827cb56975c2a54ae4f3dccdb3432be4d0b9deff9cfb0c2f243103597f9e93facb9f3 + languageName: node + linkType: hard + +"@peculiar/asn1-pkcs8@npm:^2.6.1": + version: 2.6.1 + resolution: "@peculiar/asn1-pkcs8@npm:2.6.1" + dependencies: + "@peculiar/asn1-schema": ^2.6.0 + "@peculiar/asn1-x509": ^2.6.1 + asn1js: ^3.0.6 + tslib: ^2.8.1 + checksum: 4c4ade37460af4f0ff0ce1955aecb16e488d63987a3fa9309b3c6d5fff076a05622b6f6c37c788afe463c4fb2849cf83f80fe88fe39b2934a198fd3a8396de33 + languageName: node + linkType: hard + +"@peculiar/asn1-pkcs9@npm:^2.6.0": + version: 2.6.1 + resolution: "@peculiar/asn1-pkcs9@npm:2.6.1" + dependencies: + "@peculiar/asn1-cms": ^2.6.1 + "@peculiar/asn1-pfx": ^2.6.1 + "@peculiar/asn1-pkcs8": ^2.6.1 + "@peculiar/asn1-schema": ^2.6.0 + "@peculiar/asn1-x509": ^2.6.1 + "@peculiar/asn1-x509-attr": ^2.6.1 + asn1js: ^3.0.6 + tslib: ^2.8.1 + checksum: 460792fa588828f06b7c4815e47321156f7ec531315ee4daa7287dc72b9165a2879350f1b44ff799e9351c80e0673b4bb637c50ca4aa196bec219d3ba02589bd + languageName: node + linkType: hard + +"@peculiar/asn1-rsa@npm:^2.6.0, @peculiar/asn1-rsa@npm:^2.6.1": + version: 2.6.1 + resolution: "@peculiar/asn1-rsa@npm:2.6.1" + dependencies: + "@peculiar/asn1-schema": ^2.6.0 + "@peculiar/asn1-x509": ^2.6.1 + asn1js: ^3.0.6 + tslib: ^2.8.1 + checksum: 90a36cbf018bad03a671a2cd5e7db46bfd2f25c53aee1b4aa20c75f726e49544eac555ef56762ed686682a2306678d9c451f3ba03f5582f6280abb15eb9c6d18 + languageName: node + linkType: hard + +"@peculiar/asn1-schema@npm:^2.6.0": + version: 2.6.0 + resolution: "@peculiar/asn1-schema@npm:2.6.0" + dependencies: + asn1js: ^3.0.6 + pvtsutils: ^1.3.6 + tslib: ^2.8.1 + checksum: 1d34d209b8db50ca1431060445fec9ab629d2decc3bcf161847877279c677ac8aa7794a7306950b63dd7535a91611df5464e4721ddb39a2f4c1109bd9a9fff73 + languageName: node + linkType: hard + +"@peculiar/asn1-x509-attr@npm:^2.6.1": + version: 2.6.1 + resolution: "@peculiar/asn1-x509-attr@npm:2.6.1" + dependencies: + "@peculiar/asn1-schema": ^2.6.0 + "@peculiar/asn1-x509": ^2.6.1 + asn1js: ^3.0.6 + tslib: ^2.8.1 + checksum: fdb0f8d0e45dfdab5bf3959dd4fc7db1e7df152c96fbe67dd1325fcb7db21004ad5a6c4a3e2c359226e3d637462fa751ef0b4e260a3c9d4c302f9e9ee39a31d6 + languageName: node + linkType: hard + +"@peculiar/asn1-x509@npm:^2.6.0, @peculiar/asn1-x509@npm:^2.6.1": + version: 2.6.1 + resolution: "@peculiar/asn1-x509@npm:2.6.1" + dependencies: + "@peculiar/asn1-schema": ^2.6.0 + asn1js: ^3.0.6 + pvtsutils: ^1.3.6 + tslib: ^2.8.1 + checksum: b032735a5811234344f7ba8a45daa836773accf85e42f80deb426509dc3e45b8d5d23e587f9b77a967cf28ec413afe4f3ea00a3ff4a500d25e684aa160683c0d + languageName: node + linkType: hard + +"@peculiar/x509@npm:^1.14.2": + version: 1.14.3 + resolution: "@peculiar/x509@npm:1.14.3" + dependencies: + "@peculiar/asn1-cms": ^2.6.0 + "@peculiar/asn1-csr": ^2.6.0 + "@peculiar/asn1-ecc": ^2.6.0 + "@peculiar/asn1-pkcs9": ^2.6.0 + "@peculiar/asn1-rsa": ^2.6.0 + "@peculiar/asn1-schema": ^2.6.0 + "@peculiar/asn1-x509": ^2.6.0 + pvtsutils: ^1.3.6 + reflect-metadata: ^0.2.2 + tslib: ^2.8.1 + tsyringe: ^4.10.0 + checksum: 9b7843dffd518fc78c07a28a4e0bcfa515c5ebe4af253cd07f632be8f1db61ec07e49725ce81276fb60e643d18376d646c47a01f38dc0f4cc9f0392a38594a7a + languageName: node + linkType: hard + "@pkgr/core@npm:^0.2.9": version: 0.2.9 resolution: "@pkgr/core@npm:0.2.9" @@ -4456,6 +6625,40 @@ __metadata: languageName: node linkType: hard +"@pnpm/config.env-replace@npm:^1.1.0": + version: 1.1.0 + resolution: "@pnpm/config.env-replace@npm:1.1.0" + checksum: a3d2b57e35eec9543d9eb085854f6e33e8102dac99fdef2fad2eebdbbfc345e93299f0c20e8eb61c1b4c7aa123bfd47c175678626f161cda65dd147c2b6e1fa0 + languageName: node + linkType: hard + +"@pnpm/network.ca-file@npm:^1.0.1": + version: 1.0.2 + resolution: "@pnpm/network.ca-file@npm:1.0.2" + dependencies: + graceful-fs: 4.2.10 + checksum: d8d0884646500576bd5390464d13db1bb9a62e32a1069293e5bddb2ad8354b354b7e2d2a35e12850025651e795e6a80ce9e601c66312504667b7e3ee7b52becc + languageName: node + linkType: hard + +"@pnpm/npm-conf@npm:^3.0.2": + version: 3.0.2 + resolution: "@pnpm/npm-conf@npm:3.0.2" + dependencies: + "@pnpm/config.env-replace": ^1.1.0 + "@pnpm/network.ca-file": ^1.0.1 + config-chain: ^1.1.11 + checksum: 8a88e8b59858ee7e37b3249d85f491821a878070f736127a1baff55e293c9d6e5db67c8945084970d0f2de5af9351ece28714c7dc1b2888998524999b800c144 + languageName: node + linkType: hard + +"@polka/url@npm:^1.0.0-next.24": + version: 1.0.0-next.29 + resolution: "@polka/url@npm:1.0.0-next.29" + checksum: 69ca11ab15a4ffec7f0b07fcc4e1f01489b3d9683a7e1867758818386575c60c213401259ba3705b8a812228d17e2bfd18e6f021194d943fff4bca389c9d4f28 + languageName: node + linkType: hard + "@popperjs/core@npm:^2.11.8": version: 2.11.8 resolution: "@popperjs/core@npm:2.11.8" @@ -4800,6 +7003,29 @@ __metadata: languageName: node linkType: hard +"@sideway/address@npm:^4.1.5": + version: 4.1.5 + resolution: "@sideway/address@npm:4.1.5" + dependencies: + "@hapi/hoek": ^9.0.0 + checksum: 3e3ea0f00b4765d86509282290368a4a5fd39a7995fdc6de42116ca19a96120858e56c2c995081def06e1c53e1f8bccc7d013f6326602bec9d56b72ee2772b9d + languageName: node + linkType: hard + +"@sideway/formula@npm:^3.0.1": + version: 3.0.1 + resolution: "@sideway/formula@npm:3.0.1" + checksum: e4beeebc9dbe2ff4ef0def15cec0165e00d1612e3d7cea0bc9ce5175c3263fc2c818b679bd558957f49400ee7be9d4e5ac90487e1625b4932e15c4aa7919c57a + languageName: node + linkType: hard + +"@sideway/pinpoint@npm:^2.0.0": + version: 2.0.0 + resolution: "@sideway/pinpoint@npm:2.0.0" + checksum: 0f4491e5897fcf5bf02c46f5c359c56a314e90ba243f42f0c100437935daa2488f20482f0f77186bd6bf43345095a95d8143ecf8b1f4d876a7bc0806aba9c3d2 + languageName: node + linkType: hard + "@sinclair/typebox@npm:^0.24.1": version: 0.24.51 resolution: "@sinclair/typebox@npm:0.24.51" @@ -4814,6 +7040,20 @@ __metadata: languageName: node linkType: hard +"@sindresorhus/is@npm:^4.6.0": + version: 4.6.0 + resolution: "@sindresorhus/is@npm:4.6.0" + checksum: 83839f13da2c29d55c97abc3bc2c55b250d33a0447554997a85c539e058e57b8da092da396e252b11ec24a0279a0bed1f537fa26302209327060643e327f81d2 + languageName: node + linkType: hard + +"@sindresorhus/is@npm:^5.2.0": + version: 5.6.0 + resolution: "@sindresorhus/is@npm:5.6.0" + checksum: 2e6e0c3acf188dcd9aea0f324ac1b6ad04c9fc672392a7b5a1218512fcde066965797eba8b9fe2108657a504388bd4a6664e6e6602555168e828a6df08b9f10e + languageName: node + linkType: hard + "@sinonjs/commons@npm:^1.7.0": version: 1.8.6 resolution: "@sinonjs/commons@npm:1.8.6" @@ -4892,6 +7132,17 @@ __metadata: languageName: node linkType: hard +"@slorber/remark-comment@npm:^1.0.0": + version: 1.0.0 + resolution: "@slorber/remark-comment@npm:1.0.0" + dependencies: + micromark-factory-space: ^1.0.0 + micromark-util-character: ^1.1.0 + micromark-util-symbol: ^1.0.1 + checksum: c96f1533d09913c57381859966f10a706afd8eb680923924af1c451f3b72f22c31e394028d7535131c10f8682d3c60206da95c50fb4f016fbbd04218c853cc88 + languageName: node + linkType: hard + "@smithy/abort-controller@npm:^4.2.8": version: 4.2.8 resolution: "@smithy/abort-controller@npm:4.2.8" @@ -5411,6 +7662,15 @@ __metadata: languageName: node linkType: hard +"@svgr/babel-plugin-add-jsx-attribute@npm:8.0.0": + version: 8.0.0 + resolution: "@svgr/babel-plugin-add-jsx-attribute@npm:8.0.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 3fc8e35d16f5abe0af5efe5851f27581225ac405d6a1ca44cda0df064cddfcc29a428c48c2e4bef6cebf627c9ac2f652a096030edb02cf5a120ce28d3c234710 + languageName: node + linkType: hard + "@svgr/babel-plugin-add-jsx-attribute@npm:^5.4.0": version: 5.4.0 resolution: "@svgr/babel-plugin-add-jsx-attribute@npm:5.4.0" @@ -5418,6 +7678,15 @@ __metadata: languageName: node linkType: hard +"@svgr/babel-plugin-remove-jsx-attribute@npm:8.0.0": + version: 8.0.0 + resolution: "@svgr/babel-plugin-remove-jsx-attribute@npm:8.0.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: ff992893c6c4ac802713ba3a97c13be34e62e6d981c813af40daabcd676df68a72a61bd1e692bb1eda3587f1b1d700ea462222ae2153bb0f46886632d4f88d08 + languageName: node + linkType: hard + "@svgr/babel-plugin-remove-jsx-attribute@npm:^5.4.0": version: 5.4.0 resolution: "@svgr/babel-plugin-remove-jsx-attribute@npm:5.4.0" @@ -5425,6 +7694,15 @@ __metadata: languageName: node linkType: hard +"@svgr/babel-plugin-remove-jsx-empty-expression@npm:8.0.0": + version: 8.0.0 + resolution: "@svgr/babel-plugin-remove-jsx-empty-expression@npm:8.0.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 0fb691b63a21bac00da3aa2dccec50d0d5a5b347ff408d60803b84410d8af168f2656e4ba1ee1f24dab0ae4e4af77901f2928752bb0434c1f6788133ec599ec8 + languageName: node + linkType: hard + "@svgr/babel-plugin-remove-jsx-empty-expression@npm:^5.0.1": version: 5.0.1 resolution: "@svgr/babel-plugin-remove-jsx-empty-expression@npm:5.0.1" @@ -5432,6 +7710,15 @@ __metadata: languageName: node linkType: hard +"@svgr/babel-plugin-replace-jsx-attribute-value@npm:8.0.0": + version: 8.0.0 + resolution: "@svgr/babel-plugin-replace-jsx-attribute-value@npm:8.0.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 1edda65ef4f4dd8f021143c8ec276a08f6baa6f733b8e8ee2e7775597bf6b97afb47fdeefd579d6ae6c959fe2e634f55cd61d99377631212228c8cfb351b8921 + languageName: node + linkType: hard + "@svgr/babel-plugin-replace-jsx-attribute-value@npm:^5.0.1": version: 5.0.1 resolution: "@svgr/babel-plugin-replace-jsx-attribute-value@npm:5.0.1" @@ -5439,6 +7726,15 @@ __metadata: languageName: node linkType: hard +"@svgr/babel-plugin-svg-dynamic-title@npm:8.0.0": + version: 8.0.0 + resolution: "@svgr/babel-plugin-svg-dynamic-title@npm:8.0.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 876cec891488992e6a9aebb8155e2bea4ec461b4718c51de36e988e00e271c6d9d01ef6be17b9effd44b2b3d7db0b41c161a5904a46ae6f38b26b387ad7f3709 + languageName: node + linkType: hard + "@svgr/babel-plugin-svg-dynamic-title@npm:^5.4.0": version: 5.4.0 resolution: "@svgr/babel-plugin-svg-dynamic-title@npm:5.4.0" @@ -5446,6 +7742,15 @@ __metadata: languageName: node linkType: hard +"@svgr/babel-plugin-svg-em-dimensions@npm:8.0.0": + version: 8.0.0 + resolution: "@svgr/babel-plugin-svg-em-dimensions@npm:8.0.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: be0e2d391164428327d9ec469a52cea7d93189c6b0e2c290999e048f597d777852f701c64dca44cd45b31ed14a7f859520326e2e4ad7c3a4545d0aa235bc7e9a + languageName: node + linkType: hard + "@svgr/babel-plugin-svg-em-dimensions@npm:^5.4.0": version: 5.4.0 resolution: "@svgr/babel-plugin-svg-em-dimensions@npm:5.4.0" @@ -5453,6 +7758,15 @@ __metadata: languageName: node linkType: hard +"@svgr/babel-plugin-transform-react-native-svg@npm:8.1.0": + version: 8.1.0 + resolution: "@svgr/babel-plugin-transform-react-native-svg@npm:8.1.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 85b434a57572f53bd2b9f0606f253e1fcf57b4a8c554ec3f2d43ed17f50d8cae200cb3aaf1ec9d626e1456e8b135dce530ae047eb0bed6d4bf98a752d6640459 + languageName: node + linkType: hard + "@svgr/babel-plugin-transform-react-native-svg@npm:^5.4.0": version: 5.4.0 resolution: "@svgr/babel-plugin-transform-react-native-svg@npm:5.4.0" @@ -5460,6 +7774,15 @@ __metadata: languageName: node linkType: hard +"@svgr/babel-plugin-transform-svg-component@npm:8.0.0": + version: 8.0.0 + resolution: "@svgr/babel-plugin-transform-svg-component@npm:8.0.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 04e2023d75693eeb0890341c40e449881184663056c249be7e5c80168e4aabb0fadd255e8d5d2dbf54b8c2a6e700efba994377135bfa4060dc4a2e860116ef8c + languageName: node + linkType: hard + "@svgr/babel-plugin-transform-svg-component@npm:^5.5.0": version: 5.5.0 resolution: "@svgr/babel-plugin-transform-svg-component@npm:5.5.0" @@ -5467,6 +7790,24 @@ __metadata: languageName: node linkType: hard +"@svgr/babel-preset@npm:8.1.0": + version: 8.1.0 + resolution: "@svgr/babel-preset@npm:8.1.0" + dependencies: + "@svgr/babel-plugin-add-jsx-attribute": 8.0.0 + "@svgr/babel-plugin-remove-jsx-attribute": 8.0.0 + "@svgr/babel-plugin-remove-jsx-empty-expression": 8.0.0 + "@svgr/babel-plugin-replace-jsx-attribute-value": 8.0.0 + "@svgr/babel-plugin-svg-dynamic-title": 8.0.0 + "@svgr/babel-plugin-svg-em-dimensions": 8.0.0 + "@svgr/babel-plugin-transform-react-native-svg": 8.1.0 + "@svgr/babel-plugin-transform-svg-component": 8.0.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 3a67930f080b8891e1e8e2595716b879c944d253112bae763dce59807ba23454d162216c8d66a0a0e3d4f38a649ecd6c387e545d1e1261dd69a68e9a3392ee08 + languageName: node + linkType: hard + "@svgr/babel-preset@npm:^5.5.0": version: 5.5.0 resolution: "@svgr/babel-preset@npm:5.5.0" @@ -5483,6 +7824,19 @@ __metadata: languageName: node linkType: hard +"@svgr/core@npm:8.1.0": + version: 8.1.0 + resolution: "@svgr/core@npm:8.1.0" + dependencies: + "@babel/core": ^7.21.3 + "@svgr/babel-preset": 8.1.0 + camelcase: ^6.2.0 + cosmiconfig: ^8.1.3 + snake-case: ^3.0.4 + checksum: da4a12865c7dc59829d58df8bd232d6c85b7115fda40da0d2f844a1a51886e2e945560596ecfc0345d37837ac457de86a931e8b8d8550e729e0c688c02250d8a + languageName: node + linkType: hard + "@svgr/core@npm:^5.5.0": version: 5.5.0 resolution: "@svgr/core@npm:5.5.0" @@ -5494,6 +7848,16 @@ __metadata: languageName: node linkType: hard +"@svgr/hast-util-to-babel-ast@npm:8.0.0": + version: 8.0.0 + resolution: "@svgr/hast-util-to-babel-ast@npm:8.0.0" + dependencies: + "@babel/types": ^7.21.3 + entities: ^4.4.0 + checksum: 88401281a38bbc7527e65ff5437970414391a86158ef4b4046c89764c156d2d39ecd7cce77be8a51994c9fb3249170cb1eb8b9128b62faaa81743ef6ed3534ab + languageName: node + linkType: hard + "@svgr/hast-util-to-babel-ast@npm:^5.5.0": version: 5.5.0 resolution: "@svgr/hast-util-to-babel-ast@npm:5.5.0" @@ -5503,6 +7867,20 @@ __metadata: languageName: node linkType: hard +"@svgr/plugin-jsx@npm:8.1.0": + version: 8.1.0 + resolution: "@svgr/plugin-jsx@npm:8.1.0" + dependencies: + "@babel/core": ^7.21.3 + "@svgr/babel-preset": 8.1.0 + "@svgr/hast-util-to-babel-ast": 8.0.0 + svg-parser: ^2.0.4 + peerDependencies: + "@svgr/core": "*" + checksum: 0418a9780753d3544912ee2dad5d2cf8d12e1ba74df8053651b3886aeda54d5f0f7d2dece0af5e0d838332c4f139a57f0dabaa3ca1afa4d1a765efce6a7656f2 + languageName: node + linkType: hard + "@svgr/plugin-jsx@npm:^5.5.0": version: 5.5.0 resolution: "@svgr/plugin-jsx@npm:5.5.0" @@ -5515,6 +7893,19 @@ __metadata: languageName: node linkType: hard +"@svgr/plugin-svgo@npm:8.1.0": + version: 8.1.0 + resolution: "@svgr/plugin-svgo@npm:8.1.0" + dependencies: + cosmiconfig: ^8.1.3 + deepmerge: ^4.3.1 + svgo: ^3.0.2 + peerDependencies: + "@svgr/core": "*" + checksum: 59d9d214cebaacca9ca71a561f463d8b7e5a68ca9443e4792a42d903acd52259b1790c0680bc6afecc3f00a255a6cbd7ea278a9f625bac443620ea58a590c2d0 + languageName: node + linkType: hard + "@svgr/plugin-svgo@npm:^5.5.0": version: 5.5.0 resolution: "@svgr/plugin-svgo@npm:5.5.0" @@ -5542,6 +7933,31 @@ __metadata: languageName: node linkType: hard +"@svgr/webpack@npm:^8.1.0": + version: 8.1.0 + resolution: "@svgr/webpack@npm:8.1.0" + dependencies: + "@babel/core": ^7.21.3 + "@babel/plugin-transform-react-constant-elements": ^7.21.3 + "@babel/preset-env": ^7.20.2 + "@babel/preset-react": ^7.18.6 + "@babel/preset-typescript": ^7.21.0 + "@svgr/core": 8.1.0 + "@svgr/plugin-jsx": 8.1.0 + "@svgr/plugin-svgo": 8.1.0 + checksum: c6eec5b0cf2fb2ecd3a7a362d272eda35330b17c76802a3481f499b5d07ff8f87b31d2571043bff399b051a1767b1e2e499dbf186104d1c06d76f9f1535fac01 + languageName: node + linkType: hard + +"@szmarczak/http-timer@npm:^5.0.1": + version: 5.0.1 + resolution: "@szmarczak/http-timer@npm:5.0.1" + dependencies: + defer-to-connect: ^2.0.1 + checksum: fc9cb993e808806692e4a3337c90ece0ec00c89f4b67e3652a356b89730da98bc824273a6d67ca84d5f33cd85f317dcd5ce39d8cc0a2f060145a608a7cb8ce92 + languageName: node + linkType: hard + "@testing-library/dom@npm:^10.4.0": version: 10.4.1 resolution: "@testing-library/dom@npm:10.4.1" @@ -5723,7 +8139,7 @@ __metadata: languageName: node linkType: hard -"@types/bonjour@npm:^3.5.9": +"@types/bonjour@npm:^3.5.13, @types/bonjour@npm:^3.5.9": version: 3.5.13 resolution: "@types/bonjour@npm:3.5.13" dependencies: @@ -5758,7 +8174,7 @@ __metadata: languageName: node linkType: hard -"@types/connect-history-api-fallback@npm:^1.3.5": +"@types/connect-history-api-fallback@npm:^1.3.5, @types/connect-history-api-fallback@npm:^1.5.4": version: 1.5.4 resolution: "@types/connect-history-api-fallback@npm:1.5.4" dependencies: @@ -5962,7 +8378,7 @@ __metadata: languageName: node linkType: hard -"@types/express-serve-static-core@npm:^4.17.33": +"@types/express-serve-static-core@npm:^4.17.21, @types/express-serve-static-core@npm:^4.17.33": version: 4.19.8 resolution: "@types/express-serve-static-core@npm:4.19.8" dependencies: @@ -5994,7 +8410,7 @@ __metadata: languageName: node linkType: hard -"@types/express@npm:^4.17.0, @types/express@npm:^4.17.13": +"@types/express@npm:^4.17.0, @types/express@npm:^4.17.13, @types/express@npm:^4.17.25": version: 4.17.25 resolution: "@types/express@npm:4.17.25" dependencies: @@ -6022,6 +8438,13 @@ __metadata: languageName: node linkType: hard +"@types/gtag.js@npm:^0.0.12": + version: 0.0.12 + resolution: "@types/gtag.js@npm:0.0.12" + checksum: 34efc27fbfd0013255b8bfd4af38ded9d5a6ba761130c76f17fd3a9585d83acc88d8005aab667cfec4bdec0e7c7217f689739799a8f61aed0edb929be58b162e + languageName: node + linkType: hard + "@types/hast@npm:^3.0.0": version: 3.0.4 resolution: "@types/hast@npm:3.0.4" @@ -6045,6 +8468,13 @@ __metadata: languageName: node linkType: hard +"@types/http-cache-semantics@npm:^4.0.2": + version: 4.2.0 + resolution: "@types/http-cache-semantics@npm:4.2.0" + checksum: c75c63c3d4204eba2dc14f5ac5cfabc1c17ee9f11e6f5ff63d5c73a6245c7e360c0ae3e95512778860f5b08f5886fbaf7400fba3d23fd8faf279f58aa9bb54bc + languageName: node + linkType: hard + "@types/http-errors@npm:*": version: 2.0.5 resolution: "@types/http-errors@npm:2.0.5" @@ -6135,7 +8565,7 @@ __metadata: languageName: node linkType: hard -"@types/mdast@npm:^4.0.0": +"@types/mdast@npm:^4.0.0, @types/mdast@npm:^4.0.2": version: 4.0.4 resolution: "@types/mdast@npm:4.0.4" dependencies: @@ -6144,6 +8574,13 @@ __metadata: languageName: node linkType: hard +"@types/mdx@npm:^2.0.0": + version: 2.0.13 + resolution: "@types/mdx@npm:2.0.13" + checksum: 195137b548e75a85f0558bb1ca5088aff1c01ae0fc64454da06085b7513a043356d0bb51ed559d3cbc7ad724ccd8cef2a7d07d014b89a47a74dff8875ceb3b15 + languageName: node + linkType: hard + "@types/methods@npm:^1.1.4": version: 1.1.4 resolution: "@types/methods@npm:1.1.4" @@ -6213,6 +8650,13 @@ __metadata: languageName: node linkType: hard +"@types/node@npm:^17.0.5": + version: 17.0.45 + resolution: "@types/node@npm:17.0.45" + checksum: aa04366b9103b7d6cfd6b2ef64182e0eaa7d4462c3f817618486ea0422984c51fc69fd0d436eae6c9e696ddfdbec9ccaa27a917f7c2e8c75c5d57827fe3d95e8 + languageName: node + linkType: hard + "@types/node@npm:^20.0.0": version: 20.19.30 resolution: "@types/node@npm:20.19.30" @@ -6246,6 +8690,13 @@ __metadata: languageName: node linkType: hard +"@types/prismjs@npm:^1.26.0": + version: 1.26.6 + resolution: "@types/prismjs@npm:1.26.6" + checksum: b61abb7370d55b549ab67d1dfab479f1f27539cebe02f051db67f0ad90f5de34df6b9fcaf340dd2f3e0217bba15d3e31c642832560ecf1779397d6950ee69478 + languageName: node + linkType: hard + "@types/prop-types@npm:*, @types/prop-types@npm:^15.7.12, @types/prop-types@npm:^15.7.14, @types/prop-types@npm:^15.7.15": version: 15.7.15 resolution: "@types/prop-types@npm:15.7.15" @@ -6301,7 +8752,18 @@ __metadata: languageName: node linkType: hard -"@types/react-router-dom@npm:^5.1.7": +"@types/react-router-config@npm:*, @types/react-router-config@npm:^5.0.7": + version: 5.0.11 + resolution: "@types/react-router-config@npm:5.0.11" + dependencies: + "@types/history": ^4.7.11 + "@types/react": "*" + "@types/react-router": ^5.1.0 + checksum: 4b72d9b71e0576e193c11e5085bbdac43f31debfa3b6ebc24666f3d646ef25c1f57f16c29b1ddd3051c881e85f8e0d4ab5a7bbd5fc215b9377f57675b210be7c + languageName: node + linkType: hard + +"@types/react-router-dom@npm:*, @types/react-router-dom@npm:^5.1.7": version: 5.3.3 resolution: "@types/react-router-dom@npm:5.3.3" dependencies: @@ -6312,7 +8774,7 @@ __metadata: languageName: node linkType: hard -"@types/react-router@npm:*": +"@types/react-router@npm:*, @types/react-router@npm:^5.1.0": version: 5.1.20 resolution: "@types/react-router@npm:5.1.20" dependencies: @@ -6357,6 +8819,22 @@ __metadata: languageName: node linkType: hard +"@types/retry@npm:0.12.2": + version: 0.12.2 + resolution: "@types/retry@npm:0.12.2" + checksum: e5675035717b39ce4f42f339657cae9637cf0c0051cf54314a6a2c44d38d91f6544be9ddc0280587789b6afd056be5d99dbe3e9f4df68c286c36321579b1bf4a + languageName: node + linkType: hard + +"@types/sax@npm:^1.2.1": + version: 1.2.7 + resolution: "@types/sax@npm:1.2.7" + dependencies: + "@types/node": "*" + checksum: 7ece5fbb5d9c8fc76ab0de2f99d705edf92f18e701d4f9d9b0647275e32eb65e656c1badf9dfaa12f4e1ff3e250561c8c9cfe79e8b5f33dd1417ac0f1804f6cc + languageName: node + linkType: hard + "@types/semver@npm:^7.3.12": version: 7.7.1 resolution: "@types/semver@npm:7.7.1" @@ -6383,7 +8861,7 @@ __metadata: languageName: node linkType: hard -"@types/serve-index@npm:^1.9.1": +"@types/serve-index@npm:^1.9.1, @types/serve-index@npm:^1.9.4": version: 1.9.4 resolution: "@types/serve-index@npm:1.9.4" dependencies: @@ -6392,7 +8870,7 @@ __metadata: languageName: node linkType: hard -"@types/serve-static@npm:^1, @types/serve-static@npm:^1.13.10": +"@types/serve-static@npm:^1, @types/serve-static@npm:^1.13.10, @types/serve-static@npm:^1.15.5": version: 1.15.10 resolution: "@types/serve-static@npm:1.15.10" dependencies: @@ -6413,7 +8891,7 @@ __metadata: languageName: node linkType: hard -"@types/sockjs@npm:^0.3.33": +"@types/sockjs@npm:^0.3.33, @types/sockjs@npm:^0.3.36": version: 0.3.36 resolution: "@types/sockjs@npm:0.3.36" dependencies: @@ -6492,7 +8970,7 @@ __metadata: languageName: node linkType: hard -"@types/ws@npm:^8.5.5": +"@types/ws@npm:^8.5.10, @types/ws@npm:^8.5.5": version: 8.18.1 resolution: "@types/ws@npm:8.18.1" dependencies: @@ -7184,7 +9662,7 @@ __metadata: languageName: node linkType: hard -"acorn-jsx@npm:^5.3.1, acorn-jsx@npm:^5.3.2": +"acorn-jsx@npm:^5.0.0, acorn-jsx@npm:^5.3.1, acorn-jsx@npm:^5.3.2": version: 5.3.2 resolution: "acorn-jsx@npm:5.3.2" peerDependencies: @@ -7200,7 +9678,7 @@ __metadata: languageName: node linkType: hard -"acorn-walk@npm:^8.1.1": +"acorn-walk@npm:^8.0.0, acorn-walk@npm:^8.1.1": version: 8.3.4 resolution: "acorn-walk@npm:8.3.4" dependencies: @@ -7218,7 +9696,7 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^8.11.0, acorn@npm:^8.15.0, acorn@npm:^8.2.4, acorn@npm:^8.4.1, acorn@npm:^8.9.0": +"acorn@npm:^8.0.0, acorn@npm:^8.0.4, acorn@npm:^8.11.0, acorn@npm:^8.15.0, acorn@npm:^8.2.4, acorn@npm:^8.4.1, acorn@npm:^8.9.0": version: 8.15.0 resolution: "acorn@npm:8.15.0" bin: @@ -7260,6 +9738,16 @@ __metadata: languageName: node linkType: hard +"aggregate-error@npm:^3.0.0": + version: 3.1.0 + resolution: "aggregate-error@npm:3.1.0" + dependencies: + clean-stack: ^2.0.0 + indent-string: ^4.0.0 + checksum: 1101a33f21baa27a2fa8e04b698271e64616b886795fd43c31068c07533c7b3facfcaf4e9e0cab3624bd88f729a592f1c901a1a229c9e490eafce411a8644b79 + languageName: node + linkType: hard + "ajv-formats@npm:^2.1.1": version: 2.1.1 resolution: "ajv-formats@npm:2.1.1" @@ -7318,6 +9806,48 @@ __metadata: languageName: node linkType: hard +"algoliasearch-helper@npm:^3.26.0": + version: 3.27.1 + resolution: "algoliasearch-helper@npm:3.27.1" + dependencies: + "@algolia/events": ^4.0.1 + peerDependencies: + algoliasearch: ">= 3.1 < 6" + checksum: 588315a777fd5e0a0f9b55e45746afc7405ccfde18b4c66aff8b09187553474cf54d8e17845bea9c8950222182b5aede7b777bb87d7636c42ee2851aeee83796 + languageName: node + linkType: hard + +"algoliasearch@npm:^5.37.0": + version: 5.48.2 + resolution: "algoliasearch@npm:5.48.2" + dependencies: + "@algolia/abtesting": 1.14.2 + "@algolia/client-abtesting": 5.48.2 + "@algolia/client-analytics": 5.48.2 + "@algolia/client-common": 5.48.2 + "@algolia/client-insights": 5.48.2 + "@algolia/client-personalization": 5.48.2 + "@algolia/client-query-suggestions": 5.48.2 + "@algolia/client-search": 5.48.2 + "@algolia/ingestion": 1.48.2 + "@algolia/monitoring": 1.48.2 + "@algolia/recommend": 5.48.2 + "@algolia/requester-browser-xhr": 5.48.2 + "@algolia/requester-fetch": 5.48.2 + "@algolia/requester-node-http": 5.48.2 + checksum: efdd98d98bf46e9e87e6702aede5a218be906ffe0f7e9e9c9c40f4792b6674dfaa0ff466e95f964e6aea0e8fc6963cdef616b35de7efad4ed1da7c66321961bb + languageName: node + linkType: hard + +"ansi-align@npm:^3.0.1": + version: 3.0.1 + resolution: "ansi-align@npm:3.0.1" + dependencies: + string-width: ^4.1.0 + checksum: 6abfa08f2141d231c257162b15292467081fa49a208593e055c866aa0455b57f3a86b5a678c190c618faa79b4c59e254493099cb700dd9cf2293c6be2c8f5d8d + languageName: node + linkType: hard + "ansi-colors@npm:^4.1.1": version: 4.1.3 resolution: "ansi-colors@npm:4.1.3" @@ -7325,7 +9855,7 @@ __metadata: languageName: node linkType: hard -"ansi-escapes@npm:^4.2.1, ansi-escapes@npm:^4.3.1": +"ansi-escapes@npm:^4.2.1, ansi-escapes@npm:^4.3.1, ansi-escapes@npm:^4.3.2": version: 4.3.2 resolution: "ansi-escapes@npm:4.3.2" dependencies: @@ -7391,6 +9921,13 @@ __metadata: languageName: node linkType: hard +"ansi-styles@npm:^6.1.0": + version: 6.2.3 + resolution: "ansi-styles@npm:6.2.3" + checksum: f1b0829cf048cce870a305819f65ce2adcebc097b6d6479e12e955fd6225df9b9eb8b497083b764df796d94383ff20016cc4dbbae5b40f36138fb65a9d33c2e2 + languageName: node + linkType: hard + "any-promise@npm:^1.0.0": version: 1.3.0 resolution: "any-promise@npm:1.3.0" @@ -7422,7 +9959,7 @@ __metadata: languageName: node linkType: hard -"arg@npm:^5.0.2": +"arg@npm:^5.0.0, arg@npm:^5.0.2": version: 5.0.2 resolution: "arg@npm:5.0.2" checksum: 6c69ada1a9943d332d9e5382393e897c500908d91d5cb735a01120d5f71daf1b339b7b8980cbeaba8fd1afc68e658a739746179e4315a26e8a28951ff9930078 @@ -7612,6 +10149,17 @@ __metadata: languageName: node linkType: hard +"asn1js@npm:^3.0.6": + version: 3.0.7 + resolution: "asn1js@npm:3.0.7" + dependencies: + pvtsutils: ^1.3.6 + pvutils: ^1.1.3 + tslib: ^2.8.1 + checksum: 33c4ca5349c8eb706f850ae79dbc30aabf96d6c65fe6ea120d0092e897bfc66d88583be502f995950f7c212ec729af217ba03bc4e16edf6ea27541a68540831d + languageName: node + linkType: hard + "assertion-error@npm:^2.0.1": version: 2.0.1 resolution: "assertion-error@npm:2.0.1" @@ -7633,6 +10181,15 @@ __metadata: languageName: node linkType: hard +"astring@npm:^1.8.0": + version: 1.9.0 + resolution: "astring@npm:1.9.0" + bin: + astring: bin/astring + checksum: 69ffde3643f5280c6846231a995af878a94d3eab41d1a19a86b8c15f456453f63a7982cf5dd72d270b9f50dd26763a3e1e48377c961b7df16f550132b6dba805 + languageName: node + linkType: hard + "async-function@npm:^1.0.0": version: 1.0.0 resolution: "async-function@npm:1.0.0" @@ -7685,6 +10242,23 @@ __metadata: languageName: node linkType: hard +"autoprefixer@npm:^10.4.19, autoprefixer@npm:^10.4.23": + version: 10.4.24 + resolution: "autoprefixer@npm:10.4.24" + dependencies: + browserslist: ^4.28.1 + caniuse-lite: ^1.0.30001766 + fraction.js: ^5.3.4 + picocolors: ^1.1.1 + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.1.0 + bin: + autoprefixer: bin/autoprefixer + checksum: c13d69ab38ee3646b2935a2462df45a48447d393eb8f01d2d8c65311dff40b7ae3b8ea0d868b279cfc13802c8c5d119150f63e5bf20013eb93b09b3314c6424e + languageName: node + linkType: hard + "available-typed-arrays@npm:^1.0.7": version: 1.0.7 resolution: "available-typed-arrays@npm:1.0.7" @@ -7752,6 +10326,28 @@ __metadata: languageName: node linkType: hard +"babel-loader@npm:^9.2.1": + version: 9.2.1 + resolution: "babel-loader@npm:9.2.1" + dependencies: + find-cache-dir: ^4.0.0 + schema-utils: ^4.0.0 + peerDependencies: + "@babel/core": ^7.12.0 + webpack: ">=5" + checksum: e1858d7625ad7cc8cabe6bbb8657f957041ffb1308375f359e92aa1654f413bfbb86a281bbf7cd4f7fff374d571c637b117551deac0231d779a198d4e4e78331 + languageName: node + linkType: hard + +"babel-plugin-dynamic-import-node@npm:^2.3.3": + version: 2.3.3 + resolution: "babel-plugin-dynamic-import-node@npm:2.3.3" + dependencies: + object.assign: ^4.1.0 + checksum: c9d24415bcc608d0db7d4c8540d8002ac2f94e2573d2eadced137a29d9eab7e25d2cbb4bc6b9db65cf6ee7430f7dd011d19c911a9a778f0533b4a05ce8292c9b + languageName: node + linkType: hard + "babel-plugin-istanbul@npm:^6.1.1": version: 6.1.1 resolution: "babel-plugin-istanbul@npm:6.1.1" @@ -7810,6 +10406,19 @@ __metadata: languageName: node linkType: hard +"babel-plugin-polyfill-corejs2@npm:^0.4.15": + version: 0.4.15 + resolution: "babel-plugin-polyfill-corejs2@npm:0.4.15" + dependencies: + "@babel/compat-data": ^7.28.6 + "@babel/helper-define-polyfill-provider": ^0.6.6 + semver: ^6.3.1 + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: cf32e00ee54cdd75a3acec408f3467edc20cff4359c2bc5fb221144a489d6c0d5936031e18d66483613194a7012034b8a9e1237b84e9063f963f352efc1558bc + languageName: node + linkType: hard + "babel-plugin-polyfill-corejs3@npm:^0.13.0": version: 0.13.0 resolution: "babel-plugin-polyfill-corejs3@npm:0.13.0" @@ -7822,6 +10431,18 @@ __metadata: languageName: node linkType: hard +"babel-plugin-polyfill-corejs3@npm:^0.14.0": + version: 0.14.0 + resolution: "babel-plugin-polyfill-corejs3@npm:0.14.0" + dependencies: + "@babel/helper-define-polyfill-provider": ^0.6.6 + core-js-compat: ^3.48.0 + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: dda87e15dd4e36e989fafe3719d9e67ad1ebcfae3530d1b46f285439ecdd1709b147d7a656b10091b37f6490630836fe454755bc8f829d237ada1ac44603ff81 + languageName: node + linkType: hard + "babel-plugin-polyfill-regenerator@npm:^0.6.5": version: 0.6.5 resolution: "babel-plugin-polyfill-regenerator@npm:0.6.5" @@ -7833,6 +10454,17 @@ __metadata: languageName: node linkType: hard +"babel-plugin-polyfill-regenerator@npm:^0.6.6": + version: 0.6.6 + resolution: "babel-plugin-polyfill-regenerator@npm:0.6.6" + dependencies: + "@babel/helper-define-polyfill-provider": ^0.6.6 + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: 8de7ea32856e75784601cacf8f4e3cbf04ce1fd05d56614b08b7bbe0674d1e59e37ccaa1c7ed16e3b181a63abe5bd43a1ab0e28b8c95618a9ebf0be5e24d6b25 + languageName: node + linkType: hard + "babel-plugin-transform-react-remove-prop-types@npm:^0.4.24": version: 0.4.24 resolution: "babel-plugin-transform-react-remove-prop-types@npm:0.4.24" @@ -8076,7 +10708,7 @@ __metadata: languageName: node linkType: hard -"bonjour-service@npm:^1.0.11": +"bonjour-service@npm:^1.0.11, bonjour-service@npm:^1.2.1": version: 1.3.0 resolution: "bonjour-service@npm:1.3.0" dependencies: @@ -8109,6 +10741,38 @@ __metadata: languageName: node linkType: hard +"boxen@npm:^6.2.1": + version: 6.2.1 + resolution: "boxen@npm:6.2.1" + dependencies: + ansi-align: ^3.0.1 + camelcase: ^6.2.0 + chalk: ^4.1.2 + cli-boxes: ^3.0.0 + string-width: ^5.0.1 + type-fest: ^2.5.0 + widest-line: ^4.0.1 + wrap-ansi: ^8.0.1 + checksum: 2b3226092f1ff8e149c02979098c976552afa15f9e0231c9ed2dfcaaf84604494d16a6f13b647f718439f64d3140a088e822d47c7db00d2266e9ffc8d7321774 + languageName: node + linkType: hard + +"boxen@npm:^7.0.0": + version: 7.1.1 + resolution: "boxen@npm:7.1.1" + dependencies: + ansi-align: ^3.0.1 + camelcase: ^7.0.1 + chalk: ^5.2.0 + cli-boxes: ^3.0.0 + string-width: ^5.1.2 + type-fest: ^2.13.0 + widest-line: ^4.0.1 + wrap-ansi: ^8.1.0 + checksum: ad8833d5f2845b0a728fdf8a0bc1505dff0c518edcb0fd56979a08774b1f26cf48b71e66532179ccdfb9ed95b64aa008689cca26f7776f93f002b8000a683d76 + languageName: node + linkType: hard + "brace-expansion@npm:^1.1.7": version: 1.1.12 resolution: "brace-expansion@npm:1.1.12" @@ -8160,7 +10824,7 @@ __metadata: languageName: node linkType: hard -"browserslist@npm:^4.0.0, browserslist@npm:^4.18.1, browserslist@npm:^4.21.4, browserslist@npm:^4.24.0, browserslist@npm:^4.28.0, browserslist@npm:^4.28.1": +"browserslist@npm:^4.0.0, browserslist@npm:^4.18.1, browserslist@npm:^4.21.4, browserslist@npm:^4.23.0, browserslist@npm:^4.24.0, browserslist@npm:^4.28.0, browserslist@npm:^4.28.1": version: 4.28.1 resolution: "browserslist@npm:4.28.1" dependencies: @@ -8215,6 +10879,15 @@ __metadata: languageName: node linkType: hard +"bundle-name@npm:^4.1.0": + version: 4.1.0 + resolution: "bundle-name@npm:4.1.0" + dependencies: + run-applescript: ^7.0.0 + checksum: 1d966c8d2dbf4d9d394e53b724ac756c2414c45c01340b37743621f59cc565a435024b394ddcb62b9b335d1c9a31f4640eb648c3fec7f97ee74dc0694c9beb6c + languageName: node + linkType: hard + "bundle-require@npm:^4.0.4": version: 4.2.1 resolution: "bundle-require@npm:4.2.1" @@ -8235,6 +10908,13 @@ __metadata: languageName: node linkType: hard +"bytes@npm:3.0.0": + version: 3.0.0 + resolution: "bytes@npm:3.0.0" + checksum: a2b386dd8188849a5325f58eef69c3b73c51801c08ffc6963eddc9be244089ba32d19347caf6d145c86f315ae1b1fc7061a32b0c1aa6379e6a719090287ed101 + languageName: node + linkType: hard + "bytes@npm:3.1.2, bytes@npm:^3.1.2, bytes@npm:~3.1.2": version: 3.1.2 resolution: "bytes@npm:3.1.2" @@ -8242,6 +10922,13 @@ __metadata: languageName: node linkType: hard +"bytestreamjs@npm:^2.0.1": + version: 2.0.1 + resolution: "bytestreamjs@npm:2.0.1" + checksum: db4cb039794675a0ec1f097d228e4897378cdf5f794dca04fc3bff63efb466524fcfac95e59e89e928822a80fad7574734c02b8eace9e841d8599da43c82768a + languageName: node + linkType: hard + "c12@npm:3.1.0": version: 3.1.0 resolution: "c12@npm:3.1.0" @@ -8293,6 +10980,28 @@ __metadata: languageName: node linkType: hard +"cacheable-lookup@npm:^7.0.0": + version: 7.0.0 + resolution: "cacheable-lookup@npm:7.0.0" + checksum: 9e2856763fc0a7347ab34d704c010440b819d4bb5e3593b664381b7433e942dd22e67ee5581f12256f908e79b82d30b86ebbacf40a081bfe10ee93fbfbc2d6a9 + languageName: node + linkType: hard + +"cacheable-request@npm:^10.2.8": + version: 10.2.14 + resolution: "cacheable-request@npm:10.2.14" + dependencies: + "@types/http-cache-semantics": ^4.0.2 + get-stream: ^6.0.1 + http-cache-semantics: ^4.1.1 + keyv: ^4.5.3 + mimic-response: ^4.0.0 + normalize-url: ^8.0.0 + responselike: ^3.0.0 + checksum: 56f2b8e1c497c91f8391f0b099d19907a7dde25e71087e622b23e45fc8061736c2a6964ef121b16f377c3c61079cf8dc17320ab54004209d1343e4d26aba7015 + 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" @@ -8363,6 +11072,13 @@ __metadata: languageName: node linkType: hard +"camelcase@npm:^7.0.1": + version: 7.0.1 + resolution: "camelcase@npm:7.0.1" + checksum: 86ab8f3ebf08bcdbe605a211a242f00ed30d8bfb77dab4ebb744dd36efbc84432d1c4adb28975ba87a1b8be40a80fbd1e60e2f06565315918fa7350011a26d3d + languageName: node + linkType: hard + "caniuse-api@npm:^3.0.0": version: 3.0.0 resolution: "caniuse-api@npm:3.0.0" @@ -8382,6 +11098,13 @@ __metadata: languageName: node linkType: hard +"caniuse-lite@npm:^1.0.30001766": + version: 1.0.30001770 + resolution: "caniuse-lite@npm:1.0.30001770" + checksum: 5937fdfbb274211bffb883afb2bc9ab99bea75ea9923dc96baa4eda87c110c36b036ae3d981dc28b0c52807d7ecc7c1bf6b16b4a68dbd077b26faf37ccd1887b + languageName: node + linkType: hard + "canvas-confetti@npm:^1.9.3": version: 1.9.4 resolution: "canvas-confetti@npm:1.9.4" @@ -8459,6 +11182,13 @@ __metadata: languageName: node linkType: hard +"chalk@npm:^5.0.1, chalk@npm:^5.2.0": + version: 5.6.2 + resolution: "chalk@npm:5.6.2" + checksum: 4ee2d47a626d79ca27cb5299ecdcce840ef5755e287412536522344db0fc51ca0f6d6433202332c29e2288c6a90a2b31f3bd626bc8c14743b6b6ee28abd3b796 + languageName: node + linkType: hard + "change-case@npm:^4.1.2": version: 4.1.2 resolution: "change-case@npm:4.1.2" @@ -8553,6 +11283,35 @@ __metadata: languageName: node linkType: hard +"cheerio-select@npm:^2.1.0": + version: 2.1.0 + resolution: "cheerio-select@npm:2.1.0" + dependencies: + boolbase: ^1.0.0 + css-select: ^5.1.0 + css-what: ^6.1.0 + domelementtype: ^2.3.0 + domhandler: ^5.0.3 + domutils: ^3.0.1 + checksum: 843d6d479922f28a6c5342c935aff1347491156814de63c585a6eb73baf7bb4185c1b4383a1195dca0f12e3946d737c7763bcef0b9544c515d905c5c44c5308b + languageName: node + linkType: hard + +"cheerio@npm:1.0.0-rc.12": + version: 1.0.0-rc.12 + resolution: "cheerio@npm:1.0.0-rc.12" + dependencies: + cheerio-select: ^2.1.0 + dom-serializer: ^2.0.0 + domhandler: ^5.0.3 + domutils: ^3.0.1 + htmlparser2: ^8.0.1 + parse5: ^7.0.0 + parse5-htmlparser2-tree-adapter: ^7.0.0 + checksum: 5d4c1b7a53cf22d3a2eddc0aff70cf23cbb30d01a4c79013e703a012475c02461aa1fcd99127e8d83a02216386ed6942b2c8103845fd0812300dd199e6e7e054 + languageName: node + linkType: hard + "chokidar@npm:^3.4.2, chokidar@npm:^3.5.2, chokidar@npm:^3.5.3, chokidar@npm:^3.6.0": version: 3.6.0 resolution: "chokidar@npm:3.6.0" @@ -8632,12 +11391,39 @@ __metadata: languageName: node linkType: hard -"clean-css@npm:^5.2.2": - version: 5.3.3 - resolution: "clean-css@npm:5.3.3" +"clean-css@npm:^5.2.2, clean-css@npm:^5.3.3, clean-css@npm:~5.3.2": + version: 5.3.3 + resolution: "clean-css@npm:5.3.3" + dependencies: + source-map: ~0.6.0 + checksum: 941987c14860dd7d346d5cf121a82fd2caf8344160b1565c5387f7ccca4bbcaf885bace961be37c4f4713ce2d8c488dd89483c1add47bb779790edbfdcc79cbc + languageName: node + linkType: hard + +"clean-stack@npm:^2.0.0": + version: 2.2.0 + resolution: "clean-stack@npm:2.2.0" + checksum: 2ac8cd2b2f5ec986a3c743935ec85b07bc174d5421a5efc8017e1f146a1cf5f781ae962618f416352103b32c9cd7e203276e8c28241bbe946160cab16149fb68 + languageName: node + linkType: hard + +"cli-boxes@npm:^3.0.0": + version: 3.0.0 + resolution: "cli-boxes@npm:3.0.0" + checksum: 637d84419d293a9eac40a1c8c96a2859e7d98b24a1a317788e13c8f441be052fc899480c6acab3acc82eaf1bccda6b7542d7cdcf5c9c3cc39227175dc098d5b2 + languageName: node + linkType: hard + +"cli-table3@npm:^0.6.3": + version: 0.6.5 + resolution: "cli-table3@npm:0.6.5" dependencies: - source-map: ~0.6.0 - checksum: 941987c14860dd7d346d5cf121a82fd2caf8344160b1565c5387f7ccca4bbcaf885bace961be37c4f4713ce2d8c488dd89483c1add47bb779790edbfdcc79cbc + "@colors/colors": 1.5.0 + string-width: ^4.2.0 + dependenciesMeta: + "@colors/colors": + optional: true + checksum: ab7afbf4f8597f1c631f3ee6bb3481d0bfeac8a3b81cffb5a578f145df5c88003b6cfff46046a7acae86596fdd03db382bfa67f20973b6b57425505abc47e42c languageName: node linkType: hard @@ -8681,6 +11467,17 @@ __metadata: languageName: node linkType: hard +"clone-deep@npm:^4.0.1": + version: 4.0.1 + resolution: "clone-deep@npm:4.0.1" + dependencies: + is-plain-object: ^2.0.4 + kind-of: ^6.0.2 + shallow-clone: ^3.0.0 + checksum: 770f912fe4e6f21873c8e8fbb1e99134db3b93da32df271d00589ea4a29dbe83a9808a322c93f3bcaf8584b8b4fa6fc269fc8032efbaa6728e0c9886c74467d2 + languageName: node + linkType: hard + "clsx@npm:^1.2.1": version: 1.2.1 resolution: "clsx@npm:1.2.1" @@ -8713,6 +11510,13 @@ __metadata: languageName: node linkType: hard +"collapse-white-space@npm:^2.0.0": + version: 2.1.0 + resolution: "collapse-white-space@npm:2.1.0" + checksum: c8978b1f4e7d68bf846cfdba6c6689ce8910511df7d331eb6e6757e51ceffb52768d59a28db26186c91dcf9594955b59be9f8ccd473c485790f5d8b90dc6726f + languageName: node + linkType: hard + "collect-v8-coverage@npm:^1.0.0": version: 1.0.3 resolution: "collect-v8-coverage@npm:1.0.3" @@ -8752,7 +11556,7 @@ __metadata: languageName: node linkType: hard -"colord@npm:^2.9.1": +"colord@npm:^2.9.1, colord@npm:^2.9.3": version: 2.9.3 resolution: "colord@npm:2.9.3" checksum: 95d909bfbcfd8d5605cbb5af56f2d1ce2b323990258fd7c0d2eb0e6d3bb177254d7fb8213758db56bb4ede708964f78c6b992b326615f81a18a6aaf11d64c650 @@ -8766,6 +11570,13 @@ __metadata: languageName: node linkType: hard +"combine-promises@npm:^1.1.0": + version: 1.2.0 + resolution: "combine-promises@npm:1.2.0" + checksum: ddce91436e24da03d5dc360c59cd55abfc9da5e949a26255aa42761925c574797c43138f0aabfc364e184e738e5e218a94ac6e88ebc459045bcf048ac7fe5f07 + languageName: node + linkType: hard + "combined-stream@npm:^1.0.8": version: 1.0.8 resolution: "combined-stream@npm:1.0.8" @@ -8782,6 +11593,13 @@ __metadata: languageName: node linkType: hard +"commander@npm:^10.0.0": + version: 10.0.1 + resolution: "commander@npm:10.0.1" + checksum: 436901d64a818295803c1996cd856621a74f30b9f9e28a588e726b2b1670665bccd7c1a77007ebf328729f0139838a88a19265858a0fa7a8728c4656796db948 + languageName: node + linkType: hard + "commander@npm:^2.20.0": version: 2.20.3 resolution: "commander@npm:2.20.3" @@ -8796,6 +11614,13 @@ __metadata: languageName: node linkType: hard +"commander@npm:^5.1.0": + version: 5.1.0 + resolution: "commander@npm:5.1.0" + checksum: 0b7fec1712fbcc6230fcb161d8d73b4730fa91a21dc089515489402ad78810547683f058e2a9835929c212fead1d6a6ade70db28bbb03edbc2829a9ab7d69447 + languageName: node + linkType: hard + "commander@npm:^7.2.0": version: 7.2.0 resolution: "commander@npm:7.2.0" @@ -8810,6 +11635,13 @@ __metadata: languageName: node linkType: hard +"common-path-prefix@npm:^3.0.0": + version: 3.0.0 + resolution: "common-path-prefix@npm:3.0.0" + checksum: fdb3c4f54e51e70d417ccd950c07f757582de800c0678ca388aedefefc84982039f346f9fd9a1252d08d2da9e9ef4019f580a1d1d3a10da031e4bb3c924c5818 + languageName: node + linkType: hard + "common-tags@npm:^1.8.0": version: 1.8.2 resolution: "common-tags@npm:1.8.2" @@ -8840,7 +11672,7 @@ __metadata: languageName: node linkType: hard -"compression@npm:^1.7.4": +"compression@npm:^1.7.4, compression@npm:^1.8.1": version: 1.8.1 resolution: "compression@npm:1.8.1" dependencies: @@ -8910,6 +11742,29 @@ __metadata: languageName: node linkType: hard +"config-chain@npm:^1.1.11": + version: 1.1.13 + resolution: "config-chain@npm:1.1.13" + dependencies: + ini: ^1.3.4 + proto-list: ~1.2.1 + checksum: 828137a28e7c2fc4b7fb229bd0cd6c1397bcf83434de54347e608154008f411749041ee392cbe42fab6307e02de4c12480260bf769b7d44b778fdea3839eafab + languageName: node + linkType: hard + +"configstore@npm:^6.0.0": + version: 6.0.0 + resolution: "configstore@npm:6.0.0" + dependencies: + dot-prop: ^6.0.1 + graceful-fs: ^4.2.6 + unique-string: ^3.0.0 + write-file-atomic: ^3.0.3 + xdg-basedir: ^5.0.1 + checksum: 81995351c10bc04c58507f17748477aeac6f47465109d20e3534cebc881d22e927cfd29e73dd852c46c55f62c2b7be4cd1fe6eb3a93ba51f7f9813c218f9bae0 + languageName: node + linkType: hard + "confusing-browser-globals@npm:^1.0.11": version: 1.0.11 resolution: "confusing-browser-globals@npm:1.0.11" @@ -8942,6 +11797,13 @@ __metadata: languageName: node linkType: hard +"content-disposition@npm:0.5.2": + version: 0.5.2 + resolution: "content-disposition@npm:0.5.2" + checksum: 298d7da63255a38f7858ee19c7b6aae32b167e911293174b4c1349955e97e78e1d0b0d06c10e229405987275b417cf36ff65cbd4821a98bc9df4e41e9372cde7 + languageName: node + linkType: hard + "content-disposition@npm:^1.0.0": version: 1.0.1 resolution: "content-disposition@npm:1.0.1" @@ -9031,6 +11893,22 @@ __metadata: languageName: node linkType: hard +"copy-webpack-plugin@npm:^11.0.0": + version: 11.0.0 + resolution: "copy-webpack-plugin@npm:11.0.0" + dependencies: + fast-glob: ^3.2.11 + glob-parent: ^6.0.1 + globby: ^13.1.1 + normalize-path: ^3.0.0 + schema-utils: ^4.0.0 + serialize-javascript: ^6.0.0 + peerDependencies: + webpack: ^5.1.0 + checksum: df4f8743f003a29ee7dd3d9b1789998a3a99051c92afb2ba2203d3dacfa696f4e757b275560fafb8f206e520a0aa78af34b990324a0e36c2326cefdeef3ca82e + languageName: node + linkType: hard + "core-js-compat@npm:^3.43.0": version: 3.47.0 resolution: "core-js-compat@npm:3.47.0" @@ -9040,6 +11918,15 @@ __metadata: languageName: node linkType: hard +"core-js-compat@npm:^3.48.0": + version: 3.48.0 + resolution: "core-js-compat@npm:3.48.0" + dependencies: + browserslist: ^4.28.1 + checksum: 2625622bc7c4a43a134f7d01eff48bde93100a4b5c11b6a3972bc22bcd403c6d060f26f4786ca21376fb159771f008738a5b6f283ad67b19f94e342fa8d28288 + languageName: node + linkType: hard + "core-js-pure@npm:^3.23.3": version: 3.47.0 resolution: "core-js-pure@npm:3.47.0" @@ -9047,6 +11934,13 @@ __metadata: languageName: node linkType: hard +"core-js-pure@npm:^3.48.0": + version: 3.48.0 + resolution: "core-js-pure@npm:3.48.0" + checksum: fdc8a26fa7d2cf7809c7943494660442267666a048d74739900b6a1ba7e4e52815d8203ef453d81ddd1b3dade5880a1275fefc13d884686e71a85e7fcdd69790 + languageName: node + linkType: hard + "core-js@npm:^3.19.2": version: 3.47.0 resolution: "core-js@npm:3.47.0" @@ -9054,6 +11948,13 @@ __metadata: languageName: node linkType: hard +"core-js@npm:^3.31.1": + version: 3.48.0 + resolution: "core-js@npm:3.48.0" + checksum: e5ba89a2037b06827f198b7a39bf99eaf0ad696e27001b0137f17fcc4a7fce1ecaaa4ea7b3628709ee4cf6828130a2c53ec4bdf0064e1151d46965ca5a98733f + languageName: node + linkType: hard + "core-util-is@npm:~1.0.0": version: 1.0.3 resolution: "core-util-is@npm:1.0.3" @@ -9097,6 +11998,23 @@ __metadata: languageName: node linkType: hard +"cosmiconfig@npm:^8.1.3, cosmiconfig@npm:^8.3.5": + version: 8.3.6 + resolution: "cosmiconfig@npm:8.3.6" + dependencies: + import-fresh: ^3.3.0 + js-yaml: ^4.1.0 + parse-json: ^5.2.0 + path-type: ^4.0.0 + peerDependencies: + typescript: ">=4.9.5" + peerDependenciesMeta: + typescript: + optional: true + checksum: dc339ebea427898c9e03bf01b56ba7afbac07fc7d2a2d5a15d6e9c14de98275a9565da949375aee1809591c152c0a3877bb86dbeaf74d5bd5aaa79955ad9e7a0 + languageName: node + linkType: hard + "create-require@npm:^1.1.0": version: 1.1.1 resolution: "create-require@npm:1.1.1" @@ -9122,6 +12040,15 @@ __metadata: languageName: node linkType: hard +"crypto-random-string@npm:^4.0.0": + version: 4.0.0 + resolution: "crypto-random-string@npm:4.0.0" + dependencies: + type-fest: ^1.0.1 + checksum: 91f148f27bcc8582798f0fb3e75a09d9174557f39c3c40a89dd1bd70fb5a14a02548245aa26fa7d663c426ac5026f4729841231c84f9e30e8c8ece5e38656741 + languageName: node + linkType: hard + "css-blank-pseudo@npm:^3.0.3": version: 3.0.3 resolution: "css-blank-pseudo@npm:3.0.3" @@ -9135,6 +12062,17 @@ __metadata: languageName: node linkType: hard +"css-blank-pseudo@npm:^7.0.1": + version: 7.0.1 + resolution: "css-blank-pseudo@npm:7.0.1" + dependencies: + postcss-selector-parser: ^7.0.0 + peerDependencies: + postcss: ^8.4 + checksum: 0720f013394141e129f757ffadb780a47be37fae71d195a1e8fbd02b038001bc2c3b62be83e397fe1fb1282ba656b7fce4e972d583defb6f8163e0d791c816a4 + languageName: node + linkType: hard + "css-box-model@npm:^1.2.1": version: 1.2.1 resolution: "css-box-model@npm:1.2.1" @@ -9153,6 +12091,15 @@ __metadata: languageName: node linkType: hard +"css-declaration-sorter@npm:^7.2.0": + version: 7.3.1 + resolution: "css-declaration-sorter@npm:7.3.1" + peerDependencies: + postcss: ^8.0.9 + checksum: ec56a50a1e7a8d56779d2b0de8739bfb0e271ae5002ebafff6c019cf3bb7ea64ff523c88dd23736ca20f19c3789f51c3ae928c429307266cd6abbb0baa90f19f + languageName: node + linkType: hard + "css-has-pseudo@npm:^3.0.4": version: 3.0.4 resolution: "css-has-pseudo@npm:3.0.4" @@ -9166,7 +12113,20 @@ __metadata: languageName: node linkType: hard -"css-loader@npm:^6.5.1": +"css-has-pseudo@npm:^7.0.3": + version: 7.0.3 + resolution: "css-has-pseudo@npm:7.0.3" + dependencies: + "@csstools/selector-specificity": ^5.0.0 + postcss-selector-parser: ^7.0.0 + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.4 + checksum: 93ff31d4586ee4e797bdcb4a4a2c12af95019fd34fd326937c797b2aceaad367d83655c49a17f0bf9e4ee1370e4d39a1152f58b88be0211d3ea5a234e178fa43 + languageName: node + linkType: hard + +"css-loader@npm:^6.11.0, css-loader@npm:^6.5.1": version: 6.11.0 resolution: "css-loader@npm:6.11.0" dependencies: @@ -9215,6 +12175,44 @@ __metadata: languageName: node linkType: hard +"css-minimizer-webpack-plugin@npm:^5.0.1": + version: 5.0.1 + resolution: "css-minimizer-webpack-plugin@npm:5.0.1" + dependencies: + "@jridgewell/trace-mapping": ^0.3.18 + cssnano: ^6.0.1 + jest-worker: ^29.4.3 + postcss: ^8.4.24 + schema-utils: ^4.0.1 + serialize-javascript: ^6.0.1 + peerDependencies: + webpack: ^5.0.0 + peerDependenciesMeta: + "@parcel/css": + optional: true + "@swc/css": + optional: true + clean-css: + optional: true + csso: + optional: true + esbuild: + optional: true + lightningcss: + optional: true + checksum: 10055802c61d1ae72584eac03b6bd221ecbefde11d337be44a5459d8de075b38f91b80949f95cd0c3a10295615ee013f82130bfac5fe9b5b3e8e75531f232680 + languageName: node + linkType: hard + +"css-prefers-color-scheme@npm:^10.0.0": + version: 10.0.0 + resolution: "css-prefers-color-scheme@npm:10.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 02b634aac859f5b07482563e39fc415544f8b35064b6b73e93408892dccb86fbb2eff407df4ae666780ee06350601fc6cd3ca42bc05900c7062f52589723d350 + languageName: node + linkType: hard + "css-prefers-color-scheme@npm:^6.0.3": version: 6.0.3 resolution: "css-prefers-color-scheme@npm:6.0.3" @@ -9258,6 +12256,19 @@ __metadata: languageName: node linkType: hard +"css-select@npm:^5.1.0": + version: 5.2.2 + resolution: "css-select@npm:5.2.2" + dependencies: + boolbase: ^1.0.0 + css-what: ^6.1.0 + domhandler: ^5.0.2 + domutils: ^3.0.1 + nth-check: ^2.0.1 + checksum: 0ab672620c6bdfe4129dfecf202f6b90f92018b24a1a93cfbb295c24026d0163130ba4b98d7443f87246a2c1d67413798a7a5920cd102b0cfecfbc89896515aa + languageName: node + linkType: hard + "css-tree@npm:1.0.0-alpha.37": version: 1.0.0-alpha.37 resolution: "css-tree@npm:1.0.0-alpha.37" @@ -9278,6 +12289,26 @@ __metadata: languageName: node linkType: hard +"css-tree@npm:^2.3.1": + version: 2.3.1 + resolution: "css-tree@npm:2.3.1" + dependencies: + mdn-data: 2.0.30 + source-map-js: ^1.0.1 + checksum: 493cc24b5c22b05ee5314b8a0d72d8a5869491c1458017ae5ed75aeb6c3596637dbe1b11dac2548974624adec9f7a1f3a6cf40593dc1f9185eb0e8279543fbc0 + languageName: node + linkType: hard + +"css-tree@npm:~2.2.0": + version: 2.2.1 + resolution: "css-tree@npm:2.2.1" + dependencies: + mdn-data: 2.0.28 + source-map-js: ^1.0.1 + checksum: b94aa8cc2f09e6f66c91548411fcf74badcbad3e150345074715012d16333ce573596ff5dfca03c2a87edf1924716db765120f94247e919d72753628ba3aba27 + languageName: node + linkType: hard + "css-what@npm:^3.2.1": version: 3.4.2 resolution: "css-what@npm:3.4.2" @@ -9285,7 +12316,7 @@ __metadata: languageName: node linkType: hard -"css-what@npm:^6.0.1": +"css-what@npm:^6.0.1, css-what@npm:^6.1.0": version: 6.2.2 resolution: "css-what@npm:6.2.2" checksum: 4d1f07b348a638e1f8b4c72804a1e93881f35e0f541256aec5ac0497c5855df7db7ab02da030de950d4813044f6d029a14ca657e0f92c3987e4b604246235b2b @@ -9306,6 +12337,13 @@ __metadata: languageName: node linkType: hard +"cssdb@npm:^8.6.0": + version: 8.7.1 + resolution: "cssdb@npm:8.7.1" + checksum: fd79c91001b0f1b7461a1eca7071a062fb4cb3da0a3bf2d017ae8dc7463f4fb1001487875269f95c0f0430079dae622c55f961f51bc20db7b94f61a607518cf9 + languageName: node + linkType: hard + "cssesc@npm:^3.0.0": version: 3.0.0 resolution: "cssesc@npm:3.0.0" @@ -9315,6 +12353,23 @@ __metadata: languageName: node linkType: hard +"cssnano-preset-advanced@npm:^6.1.2": + version: 6.1.2 + resolution: "cssnano-preset-advanced@npm:6.1.2" + dependencies: + autoprefixer: ^10.4.19 + browserslist: ^4.23.0 + cssnano-preset-default: ^6.1.2 + postcss-discard-unused: ^6.0.5 + postcss-merge-idents: ^6.0.3 + postcss-reduce-idents: ^6.0.3 + postcss-zindex: ^6.0.2 + peerDependencies: + postcss: ^8.4.31 + checksum: cf70e27915947412730abb3075587efb66bcea58d7f1b906a7225bb4a40c9ca40150251a2ac33363d4f55bbdeb9ba000c242fa6244ee36cba2477ac07fbbe791 + languageName: node + linkType: hard + "cssnano-preset-default@npm:^5.2.14": version: 5.2.14 resolution: "cssnano-preset-default@npm:5.2.14" @@ -9354,6 +12409,46 @@ __metadata: languageName: node linkType: hard +"cssnano-preset-default@npm:^6.1.2": + version: 6.1.2 + resolution: "cssnano-preset-default@npm:6.1.2" + dependencies: + browserslist: ^4.23.0 + css-declaration-sorter: ^7.2.0 + cssnano-utils: ^4.0.2 + postcss-calc: ^9.0.1 + postcss-colormin: ^6.1.0 + postcss-convert-values: ^6.1.0 + postcss-discard-comments: ^6.0.2 + postcss-discard-duplicates: ^6.0.3 + postcss-discard-empty: ^6.0.3 + postcss-discard-overridden: ^6.0.2 + postcss-merge-longhand: ^6.0.5 + postcss-merge-rules: ^6.1.1 + postcss-minify-font-values: ^6.1.0 + postcss-minify-gradients: ^6.0.3 + postcss-minify-params: ^6.1.0 + postcss-minify-selectors: ^6.0.4 + postcss-normalize-charset: ^6.0.2 + postcss-normalize-display-values: ^6.0.2 + postcss-normalize-positions: ^6.0.2 + postcss-normalize-repeat-style: ^6.0.2 + postcss-normalize-string: ^6.0.2 + postcss-normalize-timing-functions: ^6.0.2 + postcss-normalize-unicode: ^6.1.0 + postcss-normalize-url: ^6.0.2 + postcss-normalize-whitespace: ^6.0.2 + postcss-ordered-values: ^6.0.2 + postcss-reduce-initial: ^6.1.0 + postcss-reduce-transforms: ^6.0.2 + postcss-svgo: ^6.0.3 + postcss-unique-selectors: ^6.0.4 + peerDependencies: + postcss: ^8.4.31 + checksum: 51d93e52df7141143947dc4695b5087c04b41ea153e4f4c0282ac012b62c7457c6aca244f604ae94fa3b4840903a30a1e7df38f8610e0b304d05e3065375ee56 + languageName: node + linkType: hard + "cssnano-utils@npm:^3.1.0": version: 3.1.0 resolution: "cssnano-utils@npm:3.1.0" @@ -9363,6 +12458,15 @@ __metadata: languageName: node linkType: hard +"cssnano-utils@npm:^4.0.2": + version: 4.0.2 + resolution: "cssnano-utils@npm:4.0.2" + peerDependencies: + postcss: ^8.4.31 + checksum: f04c6854e75d847c7a43aff835e003d5bc7387ddfc476f0ad3a2d63663d0cec41047d46604c1717bf6b5a8e24e54bb519e465ff78d62c7e073c7cbe2279bebaf + languageName: node + linkType: hard + "cssnano@npm:^5.0.6": version: 5.1.15 resolution: "cssnano@npm:5.1.15" @@ -9376,6 +12480,18 @@ __metadata: languageName: node linkType: hard +"cssnano@npm:^6.0.1, cssnano@npm:^6.1.2": + version: 6.1.2 + resolution: "cssnano@npm:6.1.2" + dependencies: + cssnano-preset-default: ^6.1.2 + lilconfig: ^3.1.1 + peerDependencies: + postcss: ^8.4.31 + checksum: 65aad92c5ee0089ffd4cd933c18c65edbf7634f7c3cd833a499dc948aa7e4168be22130dfe83bde07fcdc87f7c45a02d09040b7f439498208bc90b8d5a9abcc8 + languageName: node + linkType: hard + "csso@npm:^4.0.2, csso@npm:^4.2.0": version: 4.2.0 resolution: "csso@npm:4.2.0" @@ -9385,6 +12501,15 @@ __metadata: languageName: node linkType: hard +"csso@npm:^5.0.5": + version: 5.0.5 + resolution: "csso@npm:5.0.5" + dependencies: + css-tree: ~2.2.0 + checksum: 0ad858d36bf5012ed243e9ec69962a867509061986d2ee07cc040a4b26e4d062c00d4c07e5ba8d430706ceb02dd87edd30a52b5937fd45b1b6f2119c4993d59a + languageName: node + linkType: hard + "cssom@npm:^0.4.4": version: 0.4.4 resolution: "cssom@npm:0.4.4" @@ -9582,6 +12707,13 @@ __metadata: languageName: node linkType: hard +"debounce@npm:^1.2.1": + version: 1.2.1 + resolution: "debounce@npm:1.2.1" + checksum: 682a89506d9e54fb109526f4da255c5546102fbb8e3ae75eef3b04effaf5d4853756aee97475cd4650641869794e44f410eeb20ace2b18ea592287ab2038519e + languageName: node + linkType: hard + "debug@npm:2.6.9, debug@npm:^2.6.0, debug@npm:^2.6.1": version: 2.6.9 resolution: "debug@npm:2.6.9" @@ -9686,13 +12818,30 @@ __metadata: languageName: node linkType: hard -"deepmerge@npm:^4.2.2": +"deepmerge@npm:^4.2.2, deepmerge@npm:^4.3.1": version: 4.3.1 resolution: "deepmerge@npm:4.3.1" checksum: 2024c6a980a1b7128084170c4cf56b0fd58a63f2da1660dcfe977415f27b17dbe5888668b59d0b063753f3220719d5e400b7f113609489c90160bb9a5518d052 languageName: node linkType: hard +"default-browser-id@npm:^5.0.0": + version: 5.0.1 + resolution: "default-browser-id@npm:5.0.1" + checksum: 52c637637bcd76bfe974462a2f1dd75cb04784c2852935575760f82e1fd338e5e80d3c45a9b01fdbb1e450553a830bb163b004d2eca223c5573989f82232a072 + languageName: node + linkType: hard + +"default-browser@npm:^5.2.1": + version: 5.5.0 + resolution: "default-browser@npm:5.5.0" + dependencies: + bundle-name: ^4.1.0 + default-browser-id: ^5.0.0 + checksum: c5c5d84a4abd82850e98f06798a55dee87fc1064538bea00cc14c0fb2dccccbff5e9e07eeea80385fa653202d5d92509838b4239d610ddfa1c76a04a1f65e767 + languageName: node + linkType: hard + "default-gateway@npm:^6.0.3": version: 6.0.3 resolution: "default-gateway@npm:6.0.3" @@ -9702,6 +12851,13 @@ __metadata: languageName: node linkType: hard +"defer-to-connect@npm:^2.0.1": + version: 2.0.1 + resolution: "defer-to-connect@npm:2.0.1" + checksum: 8a9b50d2f25446c0bfefb55a48e90afd58f85b21bcf78e9207cd7b804354f6409032a1705c2491686e202e64fc05f147aa5aa45f9aa82627563f045937f5791b + languageName: node + linkType: hard + "define-data-property@npm:^1.0.1, define-data-property@npm:^1.1.4": version: 1.1.4 resolution: "define-data-property@npm:1.1.4" @@ -9720,6 +12876,13 @@ __metadata: languageName: node linkType: hard +"define-lazy-prop@npm:^3.0.0": + version: 3.0.0 + resolution: "define-lazy-prop@npm:3.0.0" + checksum: 54884f94caac0791bf6395a3ec530ce901cf71c47b0196b8754f3fd17edb6c0e80149c1214429d851873bb0d689dbe08dcedbb2306dc45c8534a5934723851b6 + languageName: node + linkType: hard + "define-properties@npm:^1.1.3, define-properties@npm:^1.2.1": version: 1.2.1 resolution: "define-properties@npm:1.2.1" @@ -9814,6 +12977,19 @@ __metadata: languageName: node linkType: hard +"detect-port@npm:^1.5.1": + version: 1.6.1 + resolution: "detect-port@npm:1.6.1" + dependencies: + address: ^1.0.1 + debug: 4 + bin: + detect: bin/detect-port.js + detect-port: bin/detect-port.js + checksum: 0429fa423abb15fc453face64e6ffa406e375f51f5b4421a7886962e680dc05824eae9b6ee4594ba273685c3add415ad00982b5da54802ac3de6f846173284c3 + languageName: node + linkType: hard + "devlop@npm:^1.0.0, devlop@npm:^1.1.0": version: 1.1.0 resolution: "devlop@npm:1.1.0" @@ -9958,6 +13134,17 @@ __metadata: languageName: node linkType: hard +"dom-serializer@npm:^2.0.0": + version: 2.0.0 + resolution: "dom-serializer@npm:2.0.0" + dependencies: + domelementtype: ^2.3.0 + domhandler: ^5.0.2 + entities: ^4.2.0 + checksum: cd1810544fd8cdfbd51fa2c0c1128ec3a13ba92f14e61b7650b5de421b88205fd2e3f0cc6ace82f13334114addb90ed1c2f23074a51770a8e9c1273acbc7f3e6 + languageName: node + linkType: hard + "domelementtype@npm:1": version: 1.3.1 resolution: "domelementtype@npm:1.3.1" @@ -9965,7 +13152,7 @@ __metadata: languageName: node linkType: hard -"domelementtype@npm:^2.0.1, domelementtype@npm:^2.2.0": +"domelementtype@npm:^2.0.1, domelementtype@npm:^2.2.0, domelementtype@npm:^2.3.0": version: 2.3.0 resolution: "domelementtype@npm:2.3.0" checksum: ee837a318ff702622f383409d1f5b25dd1024b692ef64d3096ff702e26339f8e345820f29a68bcdcea8cfee3531776b3382651232fbeae95612d6f0a75efb4f6 @@ -9990,6 +13177,15 @@ __metadata: languageName: node linkType: hard +"domhandler@npm:^5.0.2, domhandler@npm:^5.0.3": + version: 5.0.3 + resolution: "domhandler@npm:5.0.3" + dependencies: + domelementtype: ^2.3.0 + checksum: 0f58f4a6af63e6f3a4320aa446d28b5790a009018707bce2859dcb1d21144c7876482b5188395a188dfa974238c019e0a1e610d2fc269a12b2c192ea2b0b131c + languageName: node + linkType: hard + "domutils@npm:^1.7.0": version: 1.7.0 resolution: "domutils@npm:1.7.0" @@ -10011,6 +13207,17 @@ __metadata: languageName: node linkType: hard +"domutils@npm:^3.0.1": + version: 3.2.2 + resolution: "domutils@npm:3.2.2" + dependencies: + dom-serializer: ^2.0.0 + domelementtype: ^2.3.0 + domhandler: ^5.0.3 + checksum: ae941d56f03d857077d55dde9297e960a625229fc2b933187cc4123084d7c2d2517f58283a7336567127029f1e008449bac8ac8506d44341e29e3bb18e02f906 + languageName: node + linkType: hard + "dot-case@npm:^3.0.4": version: 3.0.4 resolution: "dot-case@npm:3.0.4" @@ -10021,6 +13228,15 @@ __metadata: languageName: node linkType: hard +"dot-prop@npm:^6.0.1": + version: 6.0.1 + resolution: "dot-prop@npm:6.0.1" + dependencies: + is-obj: ^2.0.0 + checksum: 0f47600a4b93e1dc37261da4e6909652c008832a5d3684b5bf9a9a0d3f4c67ea949a86dceed9b72f5733ed8e8e6383cc5958df3bbd0799ee317fd181f2ece700 + languageName: node + linkType: hard + "dotenv-expand@npm:^5.1.0": version: 5.1.0 resolution: "dotenv-expand@npm:5.1.0" @@ -10060,6 +13276,13 @@ __metadata: languageName: node linkType: hard +"eastasianwidth@npm:^0.2.0": + version: 0.2.0 + resolution: "eastasianwidth@npm:0.2.0" + checksum: 7d00d7cd8e49b9afa762a813faac332dee781932d6f2c848dc348939c4253f1d4564341b7af1d041853bc3f32c2ef141b58e0a4d9862c17a7f08f68df1e0f1ed + languageName: node + linkType: hard + "ecdsa-sig-formatter@npm:1.0.11, ecdsa-sig-formatter@npm:^1.0.11": version: 1.0.11 resolution: "ecdsa-sig-formatter@npm:1.0.11" @@ -10132,6 +13355,13 @@ __metadata: languageName: node linkType: hard +"emojilib@npm:^2.4.0": + version: 2.4.0 + resolution: "emojilib@npm:2.4.0" + checksum: ea241c342abda5a86ffd3a15d8f4871a616d485f700e03daea38c6ce38205847cea9f6ff8d5e962c00516b004949cc96c6e37b05559ea71a0a496faba53b56da + languageName: node + linkType: hard + "emojis-list@npm:^3.0.0": version: 3.0.0 resolution: "emojis-list@npm:3.0.0" @@ -10139,6 +13369,13 @@ __metadata: languageName: node linkType: hard +"emoticon@npm:^4.0.1": + version: 4.1.0 + resolution: "emoticon@npm:4.1.0" + checksum: b19c997ec063eef7dfacd8713e26bca8129683b58aaf6be1600723811ec5dae18974398b808ac2972183d06d00e6e51a5b88ee92e51c69680bb855776e279a64 + languageName: node + linkType: hard + "empathic@npm:2.0.0": version: 2.0.0 resolution: "empathic@npm:2.0.0" @@ -10181,6 +13418,16 @@ __metadata: languageName: node linkType: hard +"enhanced-resolve@npm:^5.19.0": + version: 5.19.0 + resolution: "enhanced-resolve@npm:5.19.0" + dependencies: + graceful-fs: ^4.2.4 + tapable: ^2.3.0 + checksum: e7b30fa85a7831c79ad7b0aa15cde50e07eb9e770bc19266005821a596cf324f79d3b580223dccbd61e01a515cf4be09e1474745a4c47ad41d2d499b860314a5 + languageName: node + linkType: hard + "enquirer@npm:^2.3.5": version: 2.4.1 resolution: "enquirer@npm:2.4.1" @@ -10191,10 +13438,24 @@ __metadata: languageName: node linkType: hard -"entities@npm:^2.0.0": - version: 2.2.0 - resolution: "entities@npm:2.2.0" - checksum: 19010dacaf0912c895ea262b4f6128574f9ccf8d4b3b65c7e8334ad0079b3706376360e28d8843ff50a78aabcb8f08f0a32dbfacdc77e47ed77ca08b713669b3 +"entities@npm:^2.0.0": + version: 2.2.0 + resolution: "entities@npm:2.2.0" + checksum: 19010dacaf0912c895ea262b4f6128574f9ccf8d4b3b65c7e8334ad0079b3706376360e28d8843ff50a78aabcb8f08f0a32dbfacdc77e47ed77ca08b713669b3 + languageName: node + linkType: hard + +"entities@npm:^4.2.0, entities@npm:^4.4.0": + version: 4.5.0 + resolution: "entities@npm:4.5.0" + checksum: 853f8ebd5b425d350bffa97dd6958143179a5938352ccae092c62d1267c4e392a039be1bae7d51b6e4ffad25f51f9617531fedf5237f15df302ccfb452cbf2d7 + languageName: node + linkType: hard + +"entities@npm:^6.0.0": + version: 6.0.1 + resolution: "entities@npm:6.0.1" + checksum: 937b952e81aca641660a6a07f70001c6821973dea3ae7f6a5013eadce94620f3ed2e9c745832d503c8811ce6e97704d8a0396159580c0e567d815234de7fdecf languageName: node linkType: hard @@ -10392,6 +13653,30 @@ __metadata: languageName: node linkType: hard +"esast-util-from-estree@npm:^2.0.0": + version: 2.0.0 + resolution: "esast-util-from-estree@npm:2.0.0" + dependencies: + "@types/estree-jsx": ^1.0.0 + devlop: ^1.0.0 + estree-util-visit: ^2.0.0 + unist-util-position-from-estree: ^2.0.0 + checksum: b9ea5b6db25decbe7c3be23a00251542641c9538499905d740d76fd5c9fea9f727ad1d0cce4f2071b6d9bb2f405f4f11acbdec9b8ea6485649cf60d886b99f28 + languageName: node + linkType: hard + +"esast-util-from-js@npm:^2.0.0": + version: 2.0.1 + resolution: "esast-util-from-js@npm:2.0.1" + dependencies: + "@types/estree-jsx": ^1.0.0 + acorn: ^8.0.0 + esast-util-from-estree: ^2.0.0 + vfile-message: ^4.0.0 + checksum: a262b94d973d8cc80227e083a7f1367028c4acf524e8f8507177626302bac567f260f75ea52321c8a9650e34c47e70bcc4f7696f710002f64b21aaa630e73e43 + languageName: node + linkType: hard + "esbuild@npm:^0.17.0": version: 0.17.19 resolution: "esbuild@npm:0.17.19" @@ -10731,6 +14016,13 @@ __metadata: languageName: node linkType: hard +"escape-goat@npm:^4.0.0": + version: 4.0.0 + resolution: "escape-goat@npm:4.0.0" + checksum: 7034e0025eec7b751074b837f10312c5b768493265bdad046347c0aadbc1e652776f7e5df94766473fecb5d3681169cc188fe9ccc1e22be53318c18be1671cc0 + languageName: node + linkType: hard + "escape-html@npm:^1.0.3, escape-html@npm:~1.0.3": version: 1.0.3 resolution: "escape-html@npm:1.0.3" @@ -10759,6 +14051,13 @@ __metadata: languageName: node linkType: hard +"escape-string-regexp@npm:^5.0.0": + version: 5.0.0 + resolution: "escape-string-regexp@npm:5.0.0" + checksum: 20daabe197f3cb198ec28546deebcf24b3dbb1a5a269184381b3116d12f0532e06007f4bc8da25669d6a7f8efb68db0758df4cd981f57bc5b57f521a3e12c59e + languageName: node + linkType: hard + "escodegen@npm:^1.8.1": version: 1.14.3 resolution: "escodegen@npm:1.14.3" @@ -11263,6 +14562,27 @@ __metadata: languageName: node linkType: hard +"estree-util-attach-comments@npm:^3.0.0": + version: 3.0.0 + resolution: "estree-util-attach-comments@npm:3.0.0" + dependencies: + "@types/estree": ^1.0.0 + checksum: 56254eaef39659e6351919ebc2ae53a37a09290a14571c19e373e9d5fad343a3403d9ad0c23ae465d6e7d08c3e572fd56fb8c793efe6434a261bf1489932dbd5 + languageName: node + linkType: hard + +"estree-util-build-jsx@npm:^3.0.0": + version: 3.0.1 + resolution: "estree-util-build-jsx@npm:3.0.1" + dependencies: + "@types/estree-jsx": ^1.0.0 + devlop: ^1.0.0 + estree-util-is-identifier-name: ^3.0.0 + estree-walker: ^3.0.0 + checksum: 185eff060eda2ba32cecd15904db4f5ba0681159fbdf54f0f6586cd9411e77e733861a833d0aee3415e1d1fd4b17edf08bc9e9872cee98e6ec7b0800e1a85064 + languageName: node + linkType: hard + "estree-util-is-identifier-name@npm:^3.0.0": version: 3.0.0 resolution: "estree-util-is-identifier-name@npm:3.0.0" @@ -11270,6 +14590,46 @@ __metadata: languageName: node linkType: hard +"estree-util-scope@npm:^1.0.0": + version: 1.0.0 + resolution: "estree-util-scope@npm:1.0.0" + dependencies: + "@types/estree": ^1.0.0 + devlop: ^1.0.0 + checksum: df2ed1b4c078002d50f7e330980e7b6f2630a1f551102203ee5000b61ed8ce5720fe7b9bc1a238a5fded5cf0f157dbe516ad6807323f037b3bb594bd1a0d61bb + languageName: node + linkType: hard + +"estree-util-to-js@npm:^2.0.0": + version: 2.0.0 + resolution: "estree-util-to-js@npm:2.0.0" + dependencies: + "@types/estree-jsx": ^1.0.0 + astring: ^1.8.0 + source-map: ^0.7.0 + checksum: 833edc94ab9978e0918f90261e0a3361bf4564fec4901f326d2237a9235d3f5fc6482da3be5acc545e702c8c7cb8bc5de5c7c71ba3b080eb1975bcfdf3923d79 + languageName: node + linkType: hard + +"estree-util-value-to-estree@npm:^3.0.1": + version: 3.5.0 + resolution: "estree-util-value-to-estree@npm:3.5.0" + dependencies: + "@types/estree": ^1.0.0 + checksum: 2966167c5aec7aa615f9046f9abd14996e0696be41316fe50ff5a5dba65d9fa3228664e721615469d2f0bdfab6db93674624054c172b18b57fc510bcfaf5cb60 + languageName: node + linkType: hard + +"estree-util-visit@npm:^2.0.0": + version: 2.0.0 + resolution: "estree-util-visit@npm:2.0.0" + dependencies: + "@types/estree-jsx": ^1.0.0 + "@types/unist": ^3.0.0 + checksum: 6444b38f224322945a6d19ea81a8828a0eec64aefb2bf1ea791fe20df496f7b7c543408d637df899e6a8e318b638f66226f16378a33c4c2b192ba5c3f891121f + languageName: node + linkType: hard + "estree-walker@npm:^1.0.1": version: 1.0.1 resolution: "estree-walker@npm:1.0.1" @@ -11277,7 +14637,7 @@ __metadata: languageName: node linkType: hard -"estree-walker@npm:^3.0.3": +"estree-walker@npm:^3.0.0, estree-walker@npm:^3.0.3": version: 3.0.3 resolution: "estree-walker@npm:3.0.3" dependencies: @@ -11293,6 +14653,13 @@ __metadata: languageName: node linkType: hard +"eta@npm:^2.2.0": + version: 2.2.0 + resolution: "eta@npm:2.2.0" + checksum: 6a09631481d4f26a9662a1eb736a65cc1cbc48e24935e6ff5d83a83b0cb509ea56d588d66d7c087d590601dc59bdabdac2356936b1b789d020eb0cf2d8304d54 + languageName: node + linkType: hard + "etag@npm:^1.8.1, etag@npm:~1.8.1": version: 1.8.1 resolution: "etag@npm:1.8.1" @@ -11300,6 +14667,16 @@ __metadata: languageName: node linkType: hard +"eval@npm:^0.1.8": + version: 0.1.8 + resolution: "eval@npm:0.1.8" + dependencies: + "@types/node": "*" + require-like: ">= 0.1.1" + checksum: d005567f394cfbe60948e34982e4637d2665030f9aa7dcac581ea6f9ec6eceb87133ed3dc0ae21764aa362485c242a731dbb6371f1f1a86807c58676431e9d1a + languageName: node + linkType: hard + "eventemitter3@npm:^4.0.0, eventemitter3@npm:^4.0.1, eventemitter3@npm:^4.0.4": version: 4.0.7 resolution: "eventemitter3@npm:4.0.7" @@ -11321,7 +14698,7 @@ __metadata: languageName: node linkType: hard -"execa@npm:^5.0.0": +"execa@npm:5.1.1, execa@npm:^5.0.0": version: 5.1.1 resolution: "execa@npm:5.1.1" dependencies: @@ -11419,7 +14796,7 @@ __metadata: languageName: node linkType: hard -"express@npm:^4.0.0, express@npm:^4.17.3": +"express@npm:^4.0.0, express@npm:^4.17.3, express@npm:^4.22.1": version: 4.22.1 resolution: "express@npm:4.22.1" dependencies: @@ -11501,6 +14878,15 @@ __metadata: languageName: node linkType: hard +"extend-shallow@npm:^2.0.1": + version: 2.0.1 + resolution: "extend-shallow@npm:2.0.1" + dependencies: + is-extendable: ^0.1.0 + checksum: 8fb58d9d7a511f4baf78d383e637bd7d2e80843bd9cd0853649108ea835208fb614da502a553acc30208e1325240bb7cc4a68473021612496bb89725483656d8 + languageName: node + linkType: hard + "extend@npm:^3.0.0, extend@npm:^3.0.2": version: 3.0.2 resolution: "extend@npm:3.0.2" @@ -11538,7 +14924,7 @@ __metadata: languageName: node linkType: hard -"fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.2": +"fast-glob@npm:^3.2.11, fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.0, fast-glob@npm:^3.3.2": version: 3.3.3 resolution: "fast-glob@npm:3.3.3" dependencies: @@ -11606,6 +14992,15 @@ __metadata: languageName: node linkType: hard +"fault@npm:^2.0.0": + version: 2.0.1 + resolution: "fault@npm:2.0.1" + dependencies: + format: ^0.2.0 + checksum: c9b30f47d95769177130a9409976a899ed31eb598450fbad5b0d39f2f5f56d5f4a9ff9257e0bee8407cb0fc3ce37165657888c6aa6d78472e403893104329b72 + languageName: node + linkType: hard + "faye-websocket@npm:^0.11.3": version: 0.11.4 resolution: "faye-websocket@npm:0.11.4" @@ -11636,6 +15031,24 @@ __metadata: languageName: node linkType: hard +"feed@npm:^4.2.2": + version: 4.2.2 + resolution: "feed@npm:4.2.2" + dependencies: + xml-js: ^1.6.11 + checksum: 2e6992a675a049511eef7bda8ca6c08cb9540cd10e8b275ec4c95d166228ec445a335fa8de990358759f248a92861e51decdcd32bf1c54737d5b7aed7c7ffe97 + languageName: node + linkType: hard + +"figures@npm:^3.2.0": + version: 3.2.0 + resolution: "figures@npm:3.2.0" + dependencies: + escape-string-regexp: ^1.0.5 + checksum: 85a6ad29e9aca80b49b817e7c89ecc4716ff14e3779d9835af554db91bac41c0f289c418923519392a1e582b4d10482ad282021330cd045bb7b80c84152f2a2b + languageName: node + linkType: hard + "file-entry-cache@npm:^6.0.1": version: 6.0.1 resolution: "file-entry-cache@npm:6.0.1" @@ -11729,6 +15142,16 @@ __metadata: languageName: node linkType: hard +"find-cache-dir@npm:^4.0.0": + version: 4.0.0 + resolution: "find-cache-dir@npm:4.0.0" + dependencies: + common-path-prefix: ^3.0.0 + pkg-dir: ^7.0.0 + checksum: 52a456a80deeb27daa3af6e06059b63bdb9cc4af4d845fc6d6229887e505ba913cd56000349caa60bc3aa59dacdb5b4c37903d4ba34c75102d83cab330b70d2f + languageName: node + linkType: hard + "find-root@npm:^1.1.0": version: 1.1.0 resolution: "find-root@npm:1.1.0" @@ -11765,6 +15188,32 @@ __metadata: languageName: node linkType: hard +"find-up@npm:^6.3.0": + version: 6.3.0 + resolution: "find-up@npm:6.3.0" + dependencies: + locate-path: ^7.1.0 + path-exists: ^5.0.0 + checksum: 9a21b7f9244a420e54c6df95b4f6fc3941efd3c3e5476f8274eb452f6a85706e7a6a90de71353ee4f091fcb4593271a6f92810a324ec542650398f928783c280 + languageName: node + linkType: hard + +"finishline-docs@workspace:docs-site": + version: 0.0.0-use.local + resolution: "finishline-docs@workspace:docs-site" + dependencies: + "@docusaurus/core": ^3.1.0 + "@docusaurus/module-type-aliases": ^3.1.0 + "@docusaurus/preset-classic": ^3.1.0 + "@docusaurus/types": ^3.1.0 + "@mdx-js/react": ^3.0.0 + clsx: ^2.0.0 + prism-react-renderer: ^2.3.0 + react: ^18.0.0 + react-dom: ^18.0.0 + languageName: unknown + linkType: soft + "finishline-express@workspace:.": version: 0.0.0-use.local resolution: "finishline-express@workspace:." @@ -11808,6 +15257,15 @@ __metadata: languageName: node linkType: hard +"flat@npm:^5.0.2": + version: 5.0.2 + resolution: "flat@npm:5.0.2" + bin: + flat: cli.js + checksum: 12a1536ac746db74881316a181499a78ef953632ddd28050b7a3a43c62ef5462e3357c8c29d76072bb635f147f7a9a1f0c02efef6b4be28f8db62ceb3d5c7f5d + languageName: node + linkType: hard + "flatted@npm:^3.2.9": version: 3.3.3 resolution: "flatted@npm:3.3.3" @@ -11865,6 +15323,13 @@ __metadata: languageName: node linkType: hard +"form-data-encoder@npm:^2.1.2": + version: 2.1.4 + resolution: "form-data-encoder@npm:2.1.4" + checksum: e0b3e5950fb69b3f32c273944620f9861f1933df9d3e42066e038e26dfb343d0f4465de9f27e0ead1a09d9df20bc2eed06a63c2ca2f8f00949e7202bae9e29dd + languageName: node + linkType: hard + "form-data@npm:^3.0.0": version: 3.0.4 resolution: "form-data@npm:3.0.4" @@ -11891,6 +15356,13 @@ __metadata: languageName: node linkType: hard +"format@npm:^0.2.0": + version: 0.2.2 + resolution: "format@npm:0.2.2" + checksum: 646a60e1336250d802509cf24fb801e43bd4a70a07510c816fa133aa42cdbc9c21e66e9cc0801bb183c5b031c9d68be62e7fbb6877756e52357850f92aa28799 + languageName: node + linkType: hard + "formidable@npm:^2.1.2": version: 2.1.5 resolution: "formidable@npm:2.1.5" @@ -12018,6 +15490,17 @@ __metadata: languageName: node linkType: hard +"fs-extra@npm:^11.1.1, fs-extra@npm:^11.2.0": + version: 11.3.3 + resolution: "fs-extra@npm:11.3.3" + dependencies: + graceful-fs: ^4.2.0 + jsonfile: ^6.0.1 + universalify: ^2.0.0 + checksum: fb2acabbd1e04bcaca90eadfe98e6ffba1523b8009afbb9f4c0aae5efbca0bd0bf6c9a6831df5af5aaacb98d3e499898be848fb0c03d31ae7b9d1b053e81c151 + languageName: node + linkType: hard + "fs-extra@npm:^9.0.0, fs-extra@npm:^9.0.1": version: 9.1.0 resolution: "fs-extra@npm:9.1.0" @@ -12228,7 +15711,7 @@ __metadata: languageName: node linkType: hard -"get-stream@npm:^6.0.0": +"get-stream@npm:^6.0.0, get-stream@npm:^6.0.1": version: 6.0.1 resolution: "get-stream@npm:6.0.1" checksum: e04ecece32c92eebf5b8c940f51468cd53554dcbb0ea725b2748be583c9523d00128137966afce410b9b051eb2ef16d657cd2b120ca8edafcf5a65e81af63cad @@ -12278,6 +15761,13 @@ __metadata: languageName: node linkType: hard +"github-slugger@npm:^1.5.0": + version: 1.5.0 + resolution: "github-slugger@npm:1.5.0" + checksum: c70988224578b3bdaa25df65973ffc8c24594a77a28550c3636e495e49d17aef5cdb04c04fa3f1744babef98c61eecc6a43299a13ea7f3cc33d680bf9053ffbe + languageName: node + linkType: hard + "glob-parent@npm:^5.1.2, glob-parent@npm:~5.1.2": version: 5.1.2 resolution: "glob-parent@npm:5.1.2" @@ -12287,7 +15777,7 @@ __metadata: languageName: node linkType: hard -"glob-parent@npm:^6.0.2": +"glob-parent@npm:^6.0.1, glob-parent@npm:^6.0.2": version: 6.0.2 resolution: "glob-parent@npm:6.0.2" dependencies: @@ -12296,6 +15786,15 @@ __metadata: languageName: node linkType: hard +"glob-to-regex.js@npm:^1.0.0, glob-to-regex.js@npm:^1.0.1": + version: 1.2.0 + resolution: "glob-to-regex.js@npm:1.2.0" + peerDependencies: + tslib: 2 + checksum: ed7797dae9469a62f581213fb4e4272a58650896935b3ccd842a3bfafc7845caffc1510e3a02c3fae647d3740b87a51b5bcc7cc621678b9abc663babcfb3088c + languageName: node + linkType: hard + "glob-to-regexp@npm:^0.4.1": version: 0.4.1 resolution: "glob-to-regexp@npm:0.4.1" @@ -12328,6 +15827,15 @@ __metadata: languageName: node linkType: hard +"global-dirs@npm:^3.0.0": + version: 3.0.1 + resolution: "global-dirs@npm:3.0.1" + dependencies: + ini: 2.0.0 + checksum: 70147b80261601fd40ac02a104581432325c1c47329706acd773f3a6ce99bb36d1d996038c85ccacd482ad22258ec233c586b6a91535b1a116b89663d49d6438 + languageName: node + linkType: hard + "global-modules@npm:^2.0.0": version: 2.0.0 resolution: "global-modules@npm:2.0.0" @@ -12388,6 +15896,19 @@ __metadata: languageName: node linkType: hard +"globby@npm:^13.1.1": + version: 13.2.2 + resolution: "globby@npm:13.2.2" + dependencies: + dir-glob: ^3.0.1 + fast-glob: ^3.3.0 + ignore: ^5.2.4 + merge2: ^1.4.1 + slash: ^4.0.0 + checksum: f3d84ced58a901b4fcc29c846983108c426631fe47e94872868b65565495f7bee7b3defd68923bd480582771fd4bbe819217803a164a618ad76f1d22f666f41e + languageName: node + linkType: hard + "google-auth-library@npm:^8.0.2, google-auth-library@npm:^8.1.1": version: 8.9.0 resolution: "google-auth-library@npm:8.9.0" @@ -12468,6 +15989,32 @@ __metadata: languageName: node linkType: hard +"got@npm:^12.1.0": + version: 12.6.1 + resolution: "got@npm:12.6.1" + dependencies: + "@sindresorhus/is": ^5.2.0 + "@szmarczak/http-timer": ^5.0.1 + cacheable-lookup: ^7.0.0 + cacheable-request: ^10.2.8 + decompress-response: ^6.0.0 + form-data-encoder: ^2.1.2 + get-stream: ^6.0.1 + http2-wrapper: ^2.1.10 + lowercase-keys: ^3.0.0 + p-cancelable: ^3.0.0 + responselike: ^3.0.0 + checksum: 3c37f5d858aca2859f9932e7609d35881d07e7f2d44c039d189396f0656896af6c77c22f2c51c563f8918be483f60ff41e219de742ab4642d4b106711baccbd5 + languageName: node + linkType: hard + +"graceful-fs@npm:4.2.10": + version: 4.2.10 + resolution: "graceful-fs@npm:4.2.10" + checksum: 3f109d70ae123951905d85032ebeae3c2a5a7a997430df00ea30df0e3a6c60cf6689b109654d6fdacd28810a053348c4d14642da1d075049e6be1ba5216218da + languageName: node + linkType: hard + "graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.11, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" @@ -12489,6 +16036,18 @@ __metadata: languageName: node linkType: hard +"gray-matter@npm:^4.0.3": + version: 4.0.3 + resolution: "gray-matter@npm:4.0.3" + dependencies: + js-yaml: ^3.13.1 + kind-of: ^6.0.2 + section-matter: ^1.0.0 + strip-bom-string: ^1.0.0 + checksum: 37717bd424344487d655392251ce8d8878a1275ee087003e61208fba3bfd59cbb73a85b2159abf742ae95e23db04964813fdc33ae18b074208428b2528205222 + languageName: node + linkType: hard + "gtoken@npm:^6.1.0": version: 6.1.2 resolution: "gtoken@npm:6.1.2" @@ -12588,6 +16147,13 @@ __metadata: languageName: node linkType: hard +"has-yarn@npm:^3.0.0": + version: 3.0.0 + resolution: "has-yarn@npm:3.0.0" + checksum: b9e14e78e0a37bc070550c862b201534287bc10e62a86ec9c1f455ffb082db42817ce9aed914bd73f1d589bbf268520e194629ff2f62ff6b98a482c4bd2dcbfb + languageName: node + linkType: hard + "hasown@npm:^2.0.2": version: 2.0.2 resolution: "hasown@npm:2.0.2" @@ -12597,6 +16163,76 @@ __metadata: languageName: node linkType: hard +"hast-util-from-parse5@npm:^8.0.0": + version: 8.0.3 + resolution: "hast-util-from-parse5@npm:8.0.3" + dependencies: + "@types/hast": ^3.0.0 + "@types/unist": ^3.0.0 + devlop: ^1.0.0 + hastscript: ^9.0.0 + property-information: ^7.0.0 + vfile: ^6.0.0 + vfile-location: ^5.0.0 + web-namespaces: ^2.0.0 + checksum: 9ca68545a957a59f2bb18c834f1b7f72cdb1fc0d6b43233faa170e721c1f41da1bb0418b477b91332973c6bc2790a09bb07971fd8f0afe98b4cd111ea9fd7c8c + languageName: node + linkType: hard + +"hast-util-parse-selector@npm:^4.0.0": + version: 4.0.0 + resolution: "hast-util-parse-selector@npm:4.0.0" + dependencies: + "@types/hast": ^3.0.0 + checksum: 76087670d3b0b50b23a6cb70bca53a6176d6608307ccdbb3ed18b650b82e7c3513bfc40348f1389dc0c5ae872b9a768851f4335f44654abd7deafd6974c52402 + languageName: node + linkType: hard + +"hast-util-raw@npm:^9.0.0": + version: 9.1.0 + resolution: "hast-util-raw@npm:9.1.0" + dependencies: + "@types/hast": ^3.0.0 + "@types/unist": ^3.0.0 + "@ungap/structured-clone": ^1.0.0 + hast-util-from-parse5: ^8.0.0 + hast-util-to-parse5: ^8.0.0 + html-void-elements: ^3.0.0 + mdast-util-to-hast: ^13.0.0 + parse5: ^7.0.0 + unist-util-position: ^5.0.0 + unist-util-visit: ^5.0.0 + vfile: ^6.0.0 + web-namespaces: ^2.0.0 + zwitch: ^2.0.0 + checksum: 778961e2d3140362665b306caade3c12df3d03c48827a2cba3534411bb443323a86ad10ed8ef798dd7ebcccb1709edc8df7a62cedc67f69dc40482b6a855f14f + languageName: node + linkType: hard + +"hast-util-to-estree@npm:^3.0.0": + version: 3.1.3 + resolution: "hast-util-to-estree@npm:3.1.3" + dependencies: + "@types/estree": ^1.0.0 + "@types/estree-jsx": ^1.0.0 + "@types/hast": ^3.0.0 + comma-separated-tokens: ^2.0.0 + devlop: ^1.0.0 + estree-util-attach-comments: ^3.0.0 + estree-util-is-identifier-name: ^3.0.0 + hast-util-whitespace: ^3.0.0 + mdast-util-mdx-expression: ^2.0.0 + mdast-util-mdx-jsx: ^3.0.0 + mdast-util-mdxjs-esm: ^2.0.0 + property-information: ^7.0.0 + space-separated-tokens: ^2.0.0 + style-to-js: ^1.0.0 + unist-util-position: ^5.0.0 + zwitch: ^2.0.0 + checksum: 1db15b3a5a5958f61ed4e5e80dd248ed4ecca7e80c9241bb20cf4ee55721fd9a37b54aeb0caf86da2645ce3ce4dd217455d64418bb30339ddfb087e441e491b7 + languageName: node + linkType: hard + "hast-util-to-jsx-runtime@npm:^2.0.0": version: 2.3.6 resolution: "hast-util-to-jsx-runtime@npm:2.3.6" @@ -12620,6 +16256,21 @@ __metadata: languageName: node linkType: hard +"hast-util-to-parse5@npm:^8.0.0": + version: 8.0.1 + resolution: "hast-util-to-parse5@npm:8.0.1" + dependencies: + "@types/hast": ^3.0.0 + comma-separated-tokens: ^2.0.0 + devlop: ^1.0.0 + property-information: ^7.0.0 + space-separated-tokens: ^2.0.0 + web-namespaces: ^2.0.0 + zwitch: ^2.0.0 + checksum: da35619354e03bb0bfc03d50873a7c9836383c384f46faa9a33b2e89c1381705ffc277c67daec059ae496084d2f404916159137456bd154a40682529b99d82ca + languageName: node + linkType: hard + "hast-util-whitespace@npm:^3.0.0": version: 3.0.0 resolution: "hast-util-whitespace@npm:3.0.0" @@ -12629,6 +16280,19 @@ __metadata: languageName: node linkType: hard +"hastscript@npm:^9.0.0": + version: 9.0.1 + resolution: "hastscript@npm:9.0.1" + dependencies: + "@types/hast": ^3.0.0 + comma-separated-tokens: ^2.0.0 + hast-util-parse-selector: ^4.0.0 + property-information: ^7.0.0 + space-separated-tokens: ^2.0.0 + checksum: 2bbb9a3c2dc43c9dec7f6599ef45e5eefb1c2a5f75d33d005dc432e92bf9d7cfb6c0d927f15a7592bb48601d2b582ea2e4b1131a716ac3f7b618a07d88f9a5d7 + languageName: node + linkType: hard + "he@npm:^1.2.0": version: 1.2.0 resolution: "he@npm:1.2.0" @@ -12713,7 +16377,7 @@ __metadata: languageName: node linkType: hard -"html-escaper@npm:^2.0.0": +"html-escaper@npm:^2.0.0, html-escaper@npm:^2.0.2": version: 2.0.2 resolution: "html-escaper@npm:2.0.2" checksum: d2df2da3ad40ca9ee3a39c5cc6475ef67c8f83c234475f24d8e9ce0dc80a2c82df8e1d6fa78ddd1e9022a586ea1bd247a615e80a5cd9273d90111ddda7d9e974 @@ -12737,6 +16401,30 @@ __metadata: languageName: node linkType: hard +"html-minifier-terser@npm:^7.2.0": + version: 7.2.0 + resolution: "html-minifier-terser@npm:7.2.0" + dependencies: + camel-case: ^4.1.2 + clean-css: ~5.3.2 + commander: ^10.0.0 + entities: ^4.4.0 + param-case: ^3.0.4 + relateurl: ^0.2.7 + terser: ^5.15.1 + bin: + html-minifier-terser: cli.js + checksum: 39feed354b5a8aafc8e910977d68cfd961d6db330a8e1a5b16a528c86b8ee7745d8945134822cf00acf7bf0d0135bf1abad650bf308bee4ea73adb003f5b8656 + languageName: node + linkType: hard + +"html-tags@npm:^3.3.1": + version: 3.3.1 + resolution: "html-tags@npm:3.3.1" + checksum: b4ef1d5a76b678e43cce46e3783d563607b1d550cab30b4f511211564574770aa8c658a400b100e588bc60b8234e59b35ff72c7851cc28f3b5403b13a2c6cbce + languageName: node + linkType: hard + "html-url-attributes@npm:^3.0.0": version: 3.0.1 resolution: "html-url-attributes@npm:3.0.1" @@ -12744,6 +16432,13 @@ __metadata: languageName: node linkType: hard +"html-void-elements@npm:^3.0.0": + version: 3.0.0 + resolution: "html-void-elements@npm:3.0.0" + checksum: 59be397525465a7489028afa064c55763d9cccd1d7d9f630cca47137317f0e897a9ca26cef7e745e7cff1abc44260cfa407742b243a54261dfacd42230e94fce + languageName: node + linkType: hard + "html-webpack-plugin@npm:^5.5.0": version: 5.6.5 resolution: "html-webpack-plugin@npm:5.6.5" @@ -12765,6 +16460,27 @@ __metadata: languageName: node linkType: hard +"html-webpack-plugin@npm:^5.6.0": + version: 5.6.6 + resolution: "html-webpack-plugin@npm:5.6.6" + dependencies: + "@types/html-minifier-terser": ^6.0.0 + html-minifier-terser: ^6.0.2 + lodash: ^4.17.21 + pretty-error: ^4.0.0 + tapable: ^2.0.0 + peerDependencies: + "@rspack/core": 0.x || 1.x + webpack: ^5.20.0 + peerDependenciesMeta: + "@rspack/core": + optional: true + webpack: + optional: true + checksum: 6aab02f4be85ed2d939bd7dff296bf4af4b7288d6523670176c143d67f7cd4163daa1070c459d1c40e75b233f7fccefae714f58c3402a78aa83dbe9378ecf76f + languageName: node + linkType: hard + "htmlparser2@npm:^6.1.0": version: 6.1.0 resolution: "htmlparser2@npm:6.1.0" @@ -12777,6 +16493,18 @@ __metadata: languageName: node linkType: hard +"htmlparser2@npm:^8.0.1": + version: 8.0.2 + resolution: "htmlparser2@npm:8.0.2" + dependencies: + domelementtype: ^2.3.0 + domhandler: ^5.0.3 + domutils: ^3.0.1 + entities: ^4.4.0 + checksum: 29167a0f9282f181da8a6d0311b76820c8a59bc9e3c87009e21968264c2987d2723d6fde5a964d4b7b6cba663fca96ffb373c06d8223a85f52a6089ced942700 + languageName: node + linkType: hard + "http-cache-semantics@npm:^4.1.1": version: 4.2.0 resolution: "http-cache-semantics@npm:4.2.0" @@ -12844,7 +16572,7 @@ __metadata: languageName: node linkType: hard -"http-proxy-middleware@npm:^2.0.3": +"http-proxy-middleware@npm:^2.0.3, http-proxy-middleware@npm:^2.0.9": version: 2.0.9 resolution: "http-proxy-middleware@npm:2.0.9" dependencies: @@ -12873,6 +16601,16 @@ __metadata: languageName: node linkType: hard +"http2-wrapper@npm:^2.1.10": + version: 2.2.1 + resolution: "http2-wrapper@npm:2.2.1" + dependencies: + quick-lru: ^5.1.1 + resolve-alpn: ^1.2.0 + checksum: e95e55e22c6fd61182ce81fecb9b7da3af680d479febe8ad870d05f7ebbc9f076e455193766f4e7934e50913bf1d8da3ba121fb5cd2928892390b58cf9d5c509 + languageName: node + linkType: hard + "https-proxy-agent@npm:^5.0.0": version: 5.0.1 resolution: "https-proxy-agent@npm:5.0.1" @@ -12900,6 +16638,13 @@ __metadata: languageName: node linkType: hard +"hyperdyperid@npm:^1.2.0": + version: 1.2.0 + resolution: "hyperdyperid@npm:1.2.0" + checksum: 210029d1c86926f09109f6317d143f8b056fc38e8dd11b0c3e3205fc6c6ff8429fb55b4b9c2bce065462719ed9d34366eced387aaa0035d93eb76b306a8547ef + languageName: node + linkType: hard + "iconv-lite@npm:0.4.24, iconv-lite@npm:~0.4.24": version: 0.4.24 resolution: "iconv-lite@npm:0.4.24" @@ -12973,13 +16718,22 @@ __metadata: languageName: node linkType: hard -"ignore@npm:^5.2.0, ignore@npm:^5.3.1": +"ignore@npm:^5.2.0, ignore@npm:^5.2.4, ignore@npm:^5.3.1": version: 5.3.2 resolution: "ignore@npm:5.3.2" checksum: 2acfd32a573260ea522ea0bfeff880af426d68f6831f973129e2ba7363f422923cf53aab62f8369cbf4667c7b25b6f8a3761b34ecdb284ea18e87a5262a865be languageName: node linkType: hard +"image-size@npm:^2.0.2": + version: 2.0.2 + resolution: "image-size@npm:2.0.2" + bin: + image-size: bin/image-size.js + checksum: 33c3fafdd8af6bb2727bca51c4bae6e6dac16e9715337a6685a1af29fcbf7a2f9ec75eeaaa61e82d20f74d6f1fa748110936e32b1dbea4521217133eb159a29d + languageName: node + linkType: hard + "immer@npm:^9.0.7": version: 9.0.21 resolution: "immer@npm:9.0.21" @@ -12994,7 +16748,7 @@ __metadata: languageName: node linkType: hard -"import-fresh@npm:^3.0.0, import-fresh@npm:^3.1.0, import-fresh@npm:^3.2.1": +"import-fresh@npm:^3.0.0, import-fresh@npm:^3.1.0, import-fresh@npm:^3.2.1, import-fresh@npm:^3.3.0": version: 3.3.1 resolution: "import-fresh@npm:3.3.1" dependencies: @@ -13004,6 +16758,13 @@ __metadata: languageName: node linkType: hard +"import-lazy@npm:^4.0.0": + version: 4.0.0 + resolution: "import-lazy@npm:4.0.0" + checksum: 22f5e51702134aef78890156738454f620e5fe7044b204ebc057c614888a1dd6fdf2ede0fdcca44d5c173fd64f65c985f19a51775b06967ef58cc3d26898df07 + languageName: node + linkType: hard + "import-local@npm:^3.0.2": version: 3.2.0 resolution: "import-local@npm:3.2.0" @@ -13030,6 +16791,13 @@ __metadata: languageName: node linkType: hard +"infima@npm:0.2.0-alpha.45": + version: 0.2.0-alpha.45 + resolution: "infima@npm:0.2.0-alpha.45" + checksum: 23e5a33b147cb3940194c23e249001e7988327bb27896b121883442bce42a532248387649eec74d008dadadcddc790fb6842f043f33c78fda35e29f0b720cf8c + languageName: node + linkType: hard + "inflight@npm:^1.0.4": version: 1.0.6 resolution: "inflight@npm:1.0.6" @@ -13054,7 +16822,14 @@ __metadata: languageName: node linkType: hard -"ini@npm:^1.3.5, ini@npm:~1.3.0": +"ini@npm:2.0.0": + version: 2.0.0 + resolution: "ini@npm:2.0.0" + checksum: e7aadc5fb2e4aefc666d74ee2160c073995a4061556b1b5b4241ecb19ad609243b9cceafe91bae49c219519394bbd31512516cb22a3b1ca6e66d869e0447e84e + languageName: node + linkType: hard + +"ini@npm:^1.3.4, ini@npm:^1.3.5, ini@npm:~1.3.0": version: 1.3.8 resolution: "ini@npm:1.3.8" checksum: dfd98b0ca3a4fc1e323e38a6c8eb8936e31a97a918d3b377649ea15bdb15d481207a0dda1021efbd86b464cae29a0d33c1d7dcaf6c5672bee17fa849bc50a1b3 @@ -13086,6 +16861,15 @@ __metadata: languageName: node linkType: hard +"invariant@npm:^2.2.4": + version: 2.2.4 + resolution: "invariant@npm:2.2.4" + dependencies: + loose-envify: ^1.0.0 + checksum: cc3182d793aad82a8d1f0af697b462939cb46066ec48bbf1707c150ad5fad6406137e91a262022c269702e01621f35ef60269f6c0d7fd178487959809acdfb14 + languageName: node + linkType: hard + "ip-address@npm:^10.0.1": version: 10.1.0 resolution: "ip-address@npm:10.1.0" @@ -13100,7 +16884,7 @@ __metadata: languageName: node linkType: hard -"ipaddr.js@npm:^2.0.1": +"ipaddr.js@npm:^2.0.1, ipaddr.js@npm:^2.1.0": version: 2.3.0 resolution: "ipaddr.js@npm:2.3.0" checksum: 275602ad56e765d6c4187c1ab1a17d415da7a263e8d3278da5bdb6db147b29c56fac7e98a3f68b05d25e0b515601f1e750c2dd8ec9a871eb93ea094643b84916 @@ -13190,6 +16974,17 @@ __metadata: languageName: node linkType: hard +"is-ci@npm:^3.0.1": + version: 3.0.1 + resolution: "is-ci@npm:3.0.1" + dependencies: + ci-info: ^3.2.0 + bin: + is-ci: bin.js + checksum: 192c66dc7826d58f803ecae624860dccf1899fc1f3ac5505284c0a5cf5f889046ffeb958fa651e5725d5705c5bcb14f055b79150ea5fcad7456a9569de60260e + languageName: node + linkType: hard + "is-core-module@npm:^2.13.0, is-core-module@npm:^2.16.1": version: 2.16.1 resolution: "is-core-module@npm:2.16.1" @@ -13236,6 +17031,15 @@ __metadata: languageName: node linkType: hard +"is-docker@npm:^3.0.0": + version: 3.0.0 + resolution: "is-docker@npm:3.0.0" + bin: + is-docker: cli.js + checksum: b698118f04feb7eaf3338922bd79cba064ea54a1c3db6ec8c0c8d8ee7613e7e5854d802d3ef646812a8a3ace81182a085dfa0a71cc68b06f3fa794b9783b3c90 + languageName: node + linkType: hard + "is-electron@npm:2.2.2": version: 2.2.2 resolution: "is-electron@npm:2.2.2" @@ -13243,6 +17047,13 @@ __metadata: languageName: node linkType: hard +"is-extendable@npm:^0.1.0": + version: 0.1.1 + resolution: "is-extendable@npm:0.1.1" + checksum: 3875571d20a7563772ecc7a5f36cb03167e9be31ad259041b4a8f73f33f885441f778cee1f1fe0085eb4bc71679b9d8c923690003a36a6a5fdf8023e6e3f0672 + languageName: node + linkType: hard + "is-extglob@npm:^2.1.1": version: 2.1.1 resolution: "is-extglob@npm:2.1.1" @@ -13302,6 +17113,27 @@ __metadata: languageName: node linkType: hard +"is-inside-container@npm:^1.0.0": + version: 1.0.0 + resolution: "is-inside-container@npm:1.0.0" + dependencies: + is-docker: ^3.0.0 + bin: + is-inside-container: cli.js + checksum: c50b75a2ab66ab3e8b92b3bc534e1ea72ca25766832c0623ac22d134116a98bcf012197d1caabe1d1c4bd5f84363d4aa5c36bb4b585fbcaf57be172cd10a1a03 + languageName: node + linkType: hard + +"is-installed-globally@npm:^0.4.0": + version: 0.4.0 + resolution: "is-installed-globally@npm:0.4.0" + dependencies: + global-dirs: ^3.0.0 + is-path-inside: ^3.0.2 + checksum: 3359840d5982d22e9b350034237b2cda2a12bac1b48a721912e1ab8e0631dd07d45a2797a120b7b87552759a65ba03e819f1bd63f2d7ab8657ec0b44ee0bf399 + languageName: node + linkType: hard + "is-map@npm:^2.0.3": version: 2.0.3 resolution: "is-map@npm:2.0.3" @@ -13323,6 +17155,13 @@ __metadata: languageName: node linkType: hard +"is-network-error@npm:^1.0.0": + version: 1.3.0 + resolution: "is-network-error@npm:1.3.0" + checksum: 56dc0b8ed9c0bb72202058f172ad0c3121cf68772e8cbba343d3775f6e2ec7877d423cbcea45f4cedcd345de8693de1b52dfe0c6fc15d652c4aa98c2abf0185a + languageName: node + linkType: hard + "is-node-process@npm:^1.2.0": version: 1.2.0 resolution: "is-node-process@npm:1.2.0" @@ -13330,6 +17169,13 @@ __metadata: languageName: node linkType: hard +"is-npm@npm:^6.0.0": + version: 6.1.0 + resolution: "is-npm@npm:6.1.0" + checksum: 54779c55419da537da77f0f41a409516148d09f1c6db9063ee6598783b309abab109ce4f540ef68c45f4dc1fec8600ed251e393029da31691fa93ce18e72243a + languageName: node + linkType: hard + "is-number-object@npm:^1.1.1": version: 1.1.1 resolution: "is-number-object@npm:1.1.1" @@ -13354,7 +17200,14 @@ __metadata: languageName: node linkType: hard -"is-path-inside@npm:^3.0.3": +"is-obj@npm:^2.0.0": + version: 2.0.0 + resolution: "is-obj@npm:2.0.0" + checksum: c9916ac8f4621962a42f5e80e7ffdb1d79a3fab7456ceaeea394cd9e0858d04f985a9ace45be44433bf605673c8be8810540fe4cc7f4266fc7526ced95af5a08 + languageName: node + linkType: hard + +"is-path-inside@npm:^3.0.2, is-path-inside@npm:^3.0.3": version: 3.0.3 resolution: "is-path-inside@npm:3.0.3" checksum: abd50f06186a052b349c15e55b182326f1936c89a78bf6c8f2b707412517c097ce04bc49a0ca221787bc44e1049f51f09a2ffb63d22899051988d3a618ba13e9 @@ -13375,6 +17228,15 @@ __metadata: languageName: node linkType: hard +"is-plain-object@npm:^2.0.4": + version: 2.0.4 + resolution: "is-plain-object@npm:2.0.4" + dependencies: + isobject: ^3.0.1 + checksum: 2a401140cfd86cabe25214956ae2cfee6fbd8186809555cd0e84574f88de7b17abacb2e477a6a658fa54c6083ecbda1e6ae404c7720244cd198903848fca70ca + languageName: node + linkType: hard + "is-potential-custom-element-name@npm:^1.0.1": version: 1.0.1 resolution: "is-potential-custom-element-name@npm:1.0.1" @@ -13510,6 +17372,22 @@ __metadata: languageName: node linkType: hard +"is-wsl@npm:^3.1.0": + version: 3.1.1 + resolution: "is-wsl@npm:3.1.1" + dependencies: + is-inside-container: ^1.0.0 + checksum: 513d95b89af0e60b43d7b17ecb7eb78edea0a439136a3da37b1b56e215379cc46a9221474ad5b2de044824ca72d7869dee6e015273dc3f71f2bb87c715f9f1dc + languageName: node + linkType: hard + +"is-yarn-global@npm:^0.4.0": + version: 0.4.1 + resolution: "is-yarn-global@npm:0.4.1" + checksum: 79ec4e6f581c53d4fefdf5f6c237f9a3ad8db29c85cdc4659e76ae345659317552052a97b7e56952aa5d94a23c798ebec8ccad72fb14d3b26dc647ddceddd716 + languageName: node + linkType: hard + "isarray@npm:0.0.1": version: 0.0.1 resolution: "isarray@npm:0.0.1" @@ -13545,6 +17423,13 @@ __metadata: languageName: node linkType: hard +"isobject@npm:^3.0.1": + version: 3.0.1 + resolution: "isobject@npm:3.0.1" + checksum: db85c4c970ce30693676487cca0e61da2ca34e8d4967c2e1309143ff910c207133a969f9e4ddb2dc6aba670aabce4e0e307146c310350b298e74a31f7d464703 + languageName: node + linkType: hard + "istanbul-lib-coverage@npm:^3.0.0, istanbul-lib-coverage@npm:^3.2.0": version: 3.2.2 resolution: "istanbul-lib-coverage@npm:3.2.2" @@ -14259,6 +18144,18 @@ __metadata: languageName: node linkType: hard +"jest-worker@npm:^29.4.3": + version: 29.7.0 + resolution: "jest-worker@npm:29.7.0" + dependencies: + "@types/node": "*" + jest-util: ^29.7.0 + merge-stream: ^2.0.0 + supports-color: ^8.0.0 + checksum: 30fff60af49675273644d408b650fc2eb4b5dcafc5a0a455f238322a8f9d8a98d847baca9d51ff197b6747f54c7901daa2287799230b856a0f48287d131f8c13 + languageName: node + linkType: hard + "jest@npm:^27.4.3": version: 27.5.1 resolution: "jest@npm:27.5.1" @@ -14277,7 +18174,7 @@ __metadata: languageName: node linkType: hard -"jiti@npm:^1.21.7": +"jiti@npm:^1.20.0, jiti@npm:^1.21.7": version: 1.21.7 resolution: "jiti@npm:1.21.7" bin: @@ -14295,6 +18192,19 @@ __metadata: languageName: node linkType: hard +"joi@npm:^17.9.2": + version: 17.13.3 + resolution: "joi@npm:17.13.3" + dependencies: + "@hapi/hoek": ^9.3.0 + "@hapi/topo": ^5.1.0 + "@sideway/address": ^4.1.5 + "@sideway/formula": ^3.0.1 + "@sideway/pinpoint": ^2.0.0 + checksum: 66ed454fee3d8e8da1ce21657fd2c7d565d98f3e539d2c5c028767e5f38cbd6297ce54df8312d1d094e62eb38f9452ebb43da4ce87321df66cf5e3f128cbc400 + languageName: node + linkType: hard + "joycon@npm:^3.1.1": version: 3.1.1 resolution: "joycon@npm:3.1.1" @@ -14596,7 +18506,7 @@ __metadata: languageName: node linkType: hard -"kind-of@npm:^6.0.2": +"kind-of@npm:^6.0.0, kind-of@npm:^6.0.2": version: 6.0.3 resolution: "kind-of@npm:6.0.3" checksum: 3ab01e7b1d440b22fe4c31f23d8d38b4d9b91d9f291df683476576493d5dfd2e03848a8b05813dd0c3f0e835bc63f433007ddeceb71f05cb25c45ae1b19c6d3b @@ -14633,6 +18543,15 @@ __metadata: languageName: node linkType: hard +"latest-version@npm:^7.0.0": + version: 7.0.0 + resolution: "latest-version@npm:7.0.0" + dependencies: + package-json: ^8.1.0 + checksum: 1f0deba00d5a34394cce4463c938811f51bbb539b131674f4bb2062c63f2cc3b80bccd56ecade3bd5932d04a34cf0a5a8a2ccc4ec9e5e6b285a9a7b3e27d0d66 + languageName: node + linkType: hard + "launch-editor@npm:^2.6.0": version: 2.12.0 resolution: "launch-editor@npm:2.12.0" @@ -14643,6 +18562,16 @@ __metadata: languageName: node linkType: hard +"launch-editor@npm:^2.6.1": + version: 2.13.0 + resolution: "launch-editor@npm:2.13.0" + dependencies: + picocolors: ^1.1.1 + shell-quote: ^1.8.3 + checksum: 87260fe657978276d71b2ee3438fc490e7d1337ab2afcd0692000e7c70b5cc88d2b69b76044ef1c82347cdb955af8f7fb1f95aa150f869d4b44a9b3e2aae4a8b + languageName: node + linkType: hard + "leven@npm:^3.1.0": version: 3.1.0 resolution: "leven@npm:3.1.0" @@ -14751,6 +18680,15 @@ __metadata: languageName: node linkType: hard +"locate-path@npm:^7.1.0": + version: 7.2.0 + resolution: "locate-path@npm:7.2.0" + dependencies: + p-locate: ^6.0.0 + checksum: c1b653bdf29beaecb3d307dfb7c44d98a2a98a02ebe353c9ad055d1ac45d6ed4e1142563d222df9b9efebc2bcb7d4c792b507fad9e7150a04c29530b7db570f8 + languageName: node + linkType: hard + "lodash.camelcase@npm:^4.3.0": version: 4.3.0 resolution: "lodash.camelcase@npm:4.3.0" @@ -14870,7 +18808,7 @@ __metadata: languageName: node linkType: hard -"loose-envify@npm:^1.0.0, loose-envify@npm:^1.2.0, loose-envify@npm:^1.3.1, loose-envify@npm:^1.4.0": +"loose-envify@npm:^1.0.0, loose-envify@npm:^1.1.0, loose-envify@npm:^1.2.0, loose-envify@npm:^1.3.1, loose-envify@npm:^1.4.0": version: 1.4.0 resolution: "loose-envify@npm:1.4.0" dependencies: @@ -14897,6 +18835,13 @@ __metadata: languageName: node linkType: hard +"lowercase-keys@npm:^3.0.0": + version: 3.0.0 + resolution: "lowercase-keys@npm:3.0.0" + checksum: 67a3f81409af969bc0c4ca0e76cd7d16adb1e25aa1c197229587eaf8671275c8c067cd421795dbca4c81be0098e4c426a086a05e30de8a9c587b7a13c0c7ccc5 + languageName: node + linkType: hard + "lru-cache@npm:^11.0.0, lru-cache@npm:^11.1.0, lru-cache@npm:^11.2.1": version: 11.2.4 resolution: "lru-cache@npm:11.2.4" @@ -15016,40 +18961,183 @@ __metadata: languageName: node linkType: hard -"match-sorter@npm:^6.0.2": - version: 6.3.4 - resolution: "match-sorter@npm:6.3.4" +"markdown-extensions@npm:^2.0.0": + version: 2.0.0 + resolution: "markdown-extensions@npm:2.0.0" + checksum: ec4ffcb0768f112e778e7ac74cb8ef22a966c168c3e6c29829f007f015b0a0b5c79c73ee8599a0c72e440e7f5cfdbf19e80e2d77b9a313b8f66e180a330cf1b2 + languageName: node + linkType: hard + +"markdown-table@npm:^2.0.0": + version: 2.0.0 + resolution: "markdown-table@npm:2.0.0" + dependencies: + repeat-string: ^1.0.0 + checksum: 9bb634a9300016cbb41216c1eab44c74b6b7083ac07872e296f900a29449cf0e260ece03fa10c3e9784ab94c61664d1d147da0315f95e1336e2bdcc025615c90 + languageName: node + linkType: hard + +"markdown-table@npm:^3.0.0": + version: 3.0.4 + resolution: "markdown-table@npm:3.0.4" + checksum: bc24b177cbb3ef170cb38c9f191476aa63f7236ebc8980317c5e91b5bf98c8fb471cf46d8920478c5e770d7f4337326f6b5b3efbf0687c2044fd332d7a64dfcb + languageName: node + linkType: hard + +"match-sorter@npm:^6.0.2": + version: 6.3.4 + resolution: "match-sorter@npm:6.3.4" + dependencies: + "@babel/runtime": ^7.23.8 + remove-accents: 0.5.0 + checksum: 950c1600173a639e216947559a389b64258d52f33aea3a6ddb97500589888b83c976a028f731f40bc08d9d8af20de7916992fabb403f38330183a1df44c7634b + 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 + +"mdast-util-directive@npm:^3.0.0": + version: 3.1.0 + resolution: "mdast-util-directive@npm:3.1.0" + dependencies: + "@types/mdast": ^4.0.0 + "@types/unist": ^3.0.0 + ccount: ^2.0.0 + devlop: ^1.0.0 + mdast-util-from-markdown: ^2.0.0 + mdast-util-to-markdown: ^2.0.0 + parse-entities: ^4.0.0 + stringify-entities: ^4.0.0 + unist-util-visit-parents: ^6.0.0 + checksum: 9c4592cb719bbf4c9e6c7761fa9d378bb7c72fbb1b60b6ef2ee74b8a7592df2f47e625e1b3c4d5d419e94d5ca8d6c8dcc474938323e324b15362583d3f63723f + languageName: node + linkType: hard + +"mdast-util-find-and-replace@npm:^3.0.0, mdast-util-find-and-replace@npm:^3.0.1": + version: 3.0.2 + resolution: "mdast-util-find-and-replace@npm:3.0.2" + dependencies: + "@types/mdast": ^4.0.0 + escape-string-regexp: ^5.0.0 + unist-util-is: ^6.0.0 + unist-util-visit-parents: ^6.0.0 + checksum: 00dde8aaf87d065034b911bdae20d17c107f5103c6ba5a3d117598c847ce005c6b03114b5603e0d07cc61fefcbb05bdb9f66100efeaa0278dbd80eda1087595f + languageName: node + linkType: hard + +"mdast-util-from-markdown@npm:^2.0.0": + version: 2.0.2 + resolution: "mdast-util-from-markdown@npm:2.0.2" + dependencies: + "@types/mdast": ^4.0.0 + "@types/unist": ^3.0.0 + decode-named-character-reference: ^1.0.0 + devlop: ^1.0.0 + mdast-util-to-string: ^4.0.0 + micromark: ^4.0.0 + micromark-util-decode-numeric-character-reference: ^2.0.0 + micromark-util-decode-string: ^2.0.0 + micromark-util-normalize-identifier: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + unist-util-stringify-position: ^4.0.0 + checksum: 1ad19f48b30ac6e0cb756070c210c78ad93c26876edfb3f75127783bc6df8b9402016d8f3e9964f3d1d5430503138ec65c145e869438727e1aa7f3cebf228fba + languageName: node + linkType: hard + +"mdast-util-frontmatter@npm:^2.0.0": + version: 2.0.1 + resolution: "mdast-util-frontmatter@npm:2.0.1" + dependencies: + "@types/mdast": ^4.0.0 + devlop: ^1.0.0 + escape-string-regexp: ^5.0.0 + mdast-util-from-markdown: ^2.0.0 + mdast-util-to-markdown: ^2.0.0 + micromark-extension-frontmatter: ^2.0.0 + checksum: 86a7c8d9eb183be2621d6d9134b9d33df2a3647e3255f68a9796e2425e25643ffae00a501e36c57d9c10973087b94aa5a2ffd865d33cdd274cc9b88cd2d90a2e + languageName: node + linkType: hard + +"mdast-util-gfm-autolink-literal@npm:^2.0.0": + version: 2.0.1 + resolution: "mdast-util-gfm-autolink-literal@npm:2.0.1" + dependencies: + "@types/mdast": ^4.0.0 + ccount: ^2.0.0 + devlop: ^1.0.0 + mdast-util-find-and-replace: ^3.0.0 + micromark-util-character: ^2.0.0 + checksum: 5630b12e072d7004cb132231c94f667fb5813486779cb0dfb0a196d7ae0e048897a43b0b37e080017adda618ddfcbea1d7bf23c0fa31c87bfc683e0898ea1cfe + languageName: node + linkType: hard + +"mdast-util-gfm-footnote@npm:^2.0.0": + version: 2.1.0 + resolution: "mdast-util-gfm-footnote@npm:2.1.0" + dependencies: + "@types/mdast": ^4.0.0 + devlop: ^1.1.0 + mdast-util-from-markdown: ^2.0.0 + mdast-util-to-markdown: ^2.0.0 + micromark-util-normalize-identifier: ^2.0.0 + checksum: a23c5531d63b254b46cbcb063b5731f56ccc9d1f038a17fa66d3994255868604a2b963f24e0f5b16dd3374743622afafcfe0c98cf90548d485bdc426ba77c618 + languageName: node + linkType: hard + +"mdast-util-gfm-strikethrough@npm:^2.0.0": + version: 2.0.0 + resolution: "mdast-util-gfm-strikethrough@npm:2.0.0" + dependencies: + "@types/mdast": ^4.0.0 + mdast-util-from-markdown: ^2.0.0 + mdast-util-to-markdown: ^2.0.0 + checksum: fe9b1d0eba9b791ff9001c008744eafe3dd7a81b085f2bf521595ce4a8e8b1b44764ad9361761ad4533af3e5d913d8ad053abec38172031d9ee32a8ebd1c7dbd + languageName: node + linkType: hard + +"mdast-util-gfm-table@npm:^2.0.0": + version: 2.0.0 + resolution: "mdast-util-gfm-table@npm:2.0.0" dependencies: - "@babel/runtime": ^7.23.8 - remove-accents: 0.5.0 - checksum: 950c1600173a639e216947559a389b64258d52f33aea3a6ddb97500589888b83c976a028f731f40bc08d9d8af20de7916992fabb403f38330183a1df44c7634b + "@types/mdast": ^4.0.0 + devlop: ^1.0.0 + markdown-table: ^3.0.0 + mdast-util-from-markdown: ^2.0.0 + mdast-util-to-markdown: ^2.0.0 + checksum: 063a627fd0993548fd63ca0c24c437baf91ba7d51d0a38820bd459bc20bf3d13d7365ef8d28dca99176dd5eb26058f7dde51190479c186dfe6af2e11202957c9 languageName: node linkType: hard -"math-intrinsics@npm:^1.1.0": - version: 1.1.0 - resolution: "math-intrinsics@npm:1.1.0" - checksum: 0e513b29d120f478c85a70f49da0b8b19bc638975eca466f2eeae0071f3ad00454c621bf66e16dd435896c208e719fc91ad79bbfba4e400fe0b372e7c1c9c9a2 +"mdast-util-gfm-task-list-item@npm:^2.0.0": + version: 2.0.0 + resolution: "mdast-util-gfm-task-list-item@npm:2.0.0" + dependencies: + "@types/mdast": ^4.0.0 + devlop: ^1.0.0 + mdast-util-from-markdown: ^2.0.0 + mdast-util-to-markdown: ^2.0.0 + checksum: 37db90c59b15330fc54d790404abf5ef9f2f83e8961c53666fe7de4aab8dd5e6b3c296b6be19797456711a89a27840291d8871ff0438e9b4e15c89d170efe072 languageName: node linkType: hard -"mdast-util-from-markdown@npm:^2.0.0": - version: 2.0.2 - resolution: "mdast-util-from-markdown@npm:2.0.2" +"mdast-util-gfm@npm:^3.0.0": + version: 3.1.0 + resolution: "mdast-util-gfm@npm:3.1.0" dependencies: - "@types/mdast": ^4.0.0 - "@types/unist": ^3.0.0 - decode-named-character-reference: ^1.0.0 - devlop: ^1.0.0 - mdast-util-to-string: ^4.0.0 - micromark: ^4.0.0 - micromark-util-decode-numeric-character-reference: ^2.0.0 - micromark-util-decode-string: ^2.0.0 - micromark-util-normalize-identifier: ^2.0.0 - micromark-util-symbol: ^2.0.0 - micromark-util-types: ^2.0.0 - unist-util-stringify-position: ^4.0.0 - checksum: 1ad19f48b30ac6e0cb756070c210c78ad93c26876edfb3f75127783bc6df8b9402016d8f3e9964f3d1d5430503138ec65c145e869438727e1aa7f3cebf228fba + mdast-util-from-markdown: ^2.0.0 + mdast-util-gfm-autolink-literal: ^2.0.0 + mdast-util-gfm-footnote: ^2.0.0 + mdast-util-gfm-strikethrough: ^2.0.0 + mdast-util-gfm-table: ^2.0.0 + mdast-util-gfm-task-list-item: ^2.0.0 + mdast-util-to-markdown: ^2.0.0 + checksum: ecdadc0b46608d03eea53366cfee8c9441ddacc49fe4e12934eff8fea06f9377d2679d9d9e43177295c09c8d7def5f48d739f99b0f6144a0e228a77f5a1c76bc languageName: node linkType: hard @@ -15087,6 +19175,19 @@ __metadata: languageName: node linkType: hard +"mdast-util-mdx@npm:^3.0.0": + version: 3.0.0 + resolution: "mdast-util-mdx@npm:3.0.0" + dependencies: + mdast-util-from-markdown: ^2.0.0 + mdast-util-mdx-expression: ^2.0.0 + mdast-util-mdx-jsx: ^3.0.0 + mdast-util-mdxjs-esm: ^2.0.0 + mdast-util-to-markdown: ^2.0.0 + checksum: e2b007d826fcd49fd57ed03e190753c8b0f7d9eff6c7cb26ba609cde15cd3a472c0cd5e4a1ee3e39a40f14be22fdb57de243e093cea0c064d6f3366cff3e3af2 + languageName: node + linkType: hard + "mdast-util-mdxjs-esm@npm:^2.0.0": version: 2.0.1 resolution: "mdast-util-mdxjs-esm@npm:2.0.1" @@ -15161,6 +19262,20 @@ __metadata: languageName: node linkType: hard +"mdn-data@npm:2.0.28": + version: 2.0.28 + resolution: "mdn-data@npm:2.0.28" + checksum: f51d587a6ebe8e426c3376c74ea6df3e19ec8241ed8e2466c9c8a3904d5d04397199ea4f15b8d34d14524b5de926d8724ae85207984be47e165817c26e49e0aa + languageName: node + linkType: hard + +"mdn-data@npm:2.0.30": + version: 2.0.30 + resolution: "mdn-data@npm:2.0.30" + checksum: d6ac5ac7439a1607df44b22738ecf83f48e66a0874e4482d6424a61c52da5cde5750f1d1229b6f5fa1b80a492be89465390da685b11f97d62b8adcc6e88189aa + languageName: node + linkType: hard + "mdn-data@npm:2.0.4": version: 2.0.4 resolution: "mdn-data@npm:2.0.4" @@ -15191,6 +19306,30 @@ __metadata: languageName: node linkType: hard +"memfs@npm:^4.43.1": + version: 4.56.10 + resolution: "memfs@npm:4.56.10" + dependencies: + "@jsonjoy.com/fs-core": 4.56.10 + "@jsonjoy.com/fs-fsa": 4.56.10 + "@jsonjoy.com/fs-node": 4.56.10 + "@jsonjoy.com/fs-node-builtins": 4.56.10 + "@jsonjoy.com/fs-node-to-fsa": 4.56.10 + "@jsonjoy.com/fs-node-utils": 4.56.10 + "@jsonjoy.com/fs-print": 4.56.10 + "@jsonjoy.com/fs-snapshot": 4.56.10 + "@jsonjoy.com/json-pack": ^1.11.0 + "@jsonjoy.com/util": ^1.9.0 + glob-to-regex.js: ^1.0.1 + thingies: ^2.5.0 + tree-dump: ^1.0.3 + tslib: ^2.0.0 + peerDependencies: + tslib: 2 + checksum: 25eb19575721872831384363fa39a5392915399dbd548a2bc872e20d020d502d2d129c77a39199303427f86a8f0c08b978c423eb52c912af0f0e46358d56c762 + languageName: node + linkType: hard + "memoize-one@npm:^6.0.0": version: 6.0.0 resolution: "memoize-one@npm:6.0.0" @@ -15269,6 +19408,202 @@ __metadata: languageName: node linkType: hard +"micromark-extension-directive@npm:^3.0.0": + version: 3.0.2 + resolution: "micromark-extension-directive@npm:3.0.2" + dependencies: + devlop: ^1.0.0 + micromark-factory-space: ^2.0.0 + micromark-factory-whitespace: ^2.0.0 + micromark-util-character: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + parse-entities: ^4.0.0 + checksum: 572c9e4625bc6a37146f6c905cbc8b507f171c07ad0a6d991d6ee22bbde4620826b89303f80e71c30c7903e5fa0661e1f08fb14e69b5273b33afbd87276c8a53 + languageName: node + linkType: hard + +"micromark-extension-frontmatter@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-extension-frontmatter@npm:2.0.0" + dependencies: + fault: ^2.0.0 + micromark-util-character: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: f68032df38c00ae47de15b63bcd72515bfcce39de4a9262a3a1ac9c5990f253f8e41bdc65fd17ec4bb3d144c32529ce0829571331e4901a9a413f1a53785d1e8 + languageName: node + linkType: hard + +"micromark-extension-gfm-autolink-literal@npm:^2.0.0": + version: 2.1.0 + resolution: "micromark-extension-gfm-autolink-literal@npm:2.1.0" + dependencies: + micromark-util-character: ^2.0.0 + micromark-util-sanitize-uri: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: e00a570c70c837b9cbbe94b2c23b787f44e781cd19b72f1828e3453abca2a9fb600fa539cdc75229fa3919db384491063645086e02249481e6ff3ec2c18f767c + languageName: node + linkType: hard + +"micromark-extension-gfm-footnote@npm:^2.0.0": + version: 2.1.0 + resolution: "micromark-extension-gfm-footnote@npm:2.1.0" + dependencies: + devlop: ^1.0.0 + micromark-core-commonmark: ^2.0.0 + micromark-factory-space: ^2.0.0 + micromark-util-character: ^2.0.0 + micromark-util-normalize-identifier: ^2.0.0 + micromark-util-sanitize-uri: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: ac6fb039e98395d37b71ebff7c7a249aef52678b5cf554c89c4f716111d4be62ef99a5d715a5bd5d68fa549778c977d85cb671d1d8506dc8a3a1b46e867ae52f + languageName: node + linkType: hard + +"micromark-extension-gfm-strikethrough@npm:^2.0.0": + version: 2.1.0 + resolution: "micromark-extension-gfm-strikethrough@npm:2.1.0" + dependencies: + devlop: ^1.0.0 + micromark-util-chunked: ^2.0.0 + micromark-util-classify-character: ^2.0.0 + micromark-util-resolve-all: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: cdb7a38dd6eefb6ceb6792a44a6796b10f951e8e3e45b8579f599f43e7ae26ccd048c0aa7e441b3c29dd0c54656944fe6eb0098de2bc4b5106fbc0a42e9e016c + languageName: node + linkType: hard + +"micromark-extension-gfm-table@npm:^2.0.0": + version: 2.1.1 + resolution: "micromark-extension-gfm-table@npm:2.1.1" + dependencies: + devlop: ^1.0.0 + micromark-factory-space: ^2.0.0 + micromark-util-character: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: 16a59c8c2381c8418d9cf36c605abb0b66cfebaad07e09c4c9b113298d13e0c517b652885529fcb74d149afec3f6e8ab065fd27a900073d5ec0a1d8f0c51b593 + languageName: node + linkType: hard + +"micromark-extension-gfm-tagfilter@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-extension-gfm-tagfilter@npm:2.0.0" + dependencies: + micromark-util-types: ^2.0.0 + checksum: cf21552f4a63592bfd6c96ae5d64a5f22bda4e77814e3f0501bfe80e7a49378ad140f827007f36044666f176b3a0d5fea7c2e8e7973ce4b4579b77789f01ae95 + languageName: node + linkType: hard + +"micromark-extension-gfm-task-list-item@npm:^2.0.0": + version: 2.1.0 + resolution: "micromark-extension-gfm-task-list-item@npm:2.1.0" + dependencies: + devlop: ^1.0.0 + micromark-factory-space: ^2.0.0 + micromark-util-character: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: b1ad86a4e9d68d9ad536d94fb25a5182acbc85cc79318f4a6316034342f6a71d67983cc13f12911d0290fd09b2bda43cdabe8781a2d9cca2ebe0d421e8b2b8a4 + languageName: node + linkType: hard + +"micromark-extension-gfm@npm:^3.0.0": + version: 3.0.0 + resolution: "micromark-extension-gfm@npm:3.0.0" + dependencies: + micromark-extension-gfm-autolink-literal: ^2.0.0 + micromark-extension-gfm-footnote: ^2.0.0 + micromark-extension-gfm-strikethrough: ^2.0.0 + micromark-extension-gfm-table: ^2.0.0 + micromark-extension-gfm-tagfilter: ^2.0.0 + micromark-extension-gfm-task-list-item: ^2.0.0 + micromark-util-combine-extensions: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: 2060fa62666a09532d6b3a272d413bc1b25bbb262f921d7402795ac021e1362c8913727e33d7528d5b4ccaf26922ec51208c43f795a702964817bc986de886c9 + languageName: node + linkType: hard + +"micromark-extension-mdx-expression@npm:^3.0.0": + version: 3.0.1 + resolution: "micromark-extension-mdx-expression@npm:3.0.1" + dependencies: + "@types/estree": ^1.0.0 + devlop: ^1.0.0 + micromark-factory-mdx-expression: ^2.0.0 + micromark-factory-space: ^2.0.0 + micromark-util-character: ^2.0.0 + micromark-util-events-to-acorn: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: 0e15bc3911b53704723acc300d99093e46e31a1f2210f6fadeaf065d04c964cd4588cf4aa1e9c324430bfd943dfa7f36e369a3bc92f4641015b107bbb2190034 + languageName: node + linkType: hard + +"micromark-extension-mdx-jsx@npm:^3.0.0": + version: 3.0.2 + resolution: "micromark-extension-mdx-jsx@npm:3.0.2" + dependencies: + "@types/estree": ^1.0.0 + devlop: ^1.0.0 + estree-util-is-identifier-name: ^3.0.0 + micromark-factory-mdx-expression: ^2.0.0 + micromark-factory-space: ^2.0.0 + micromark-util-character: ^2.0.0 + micromark-util-events-to-acorn: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + vfile-message: ^4.0.0 + checksum: abe07e592a95804445d2c667bc999696ac39ddd551374f5a39e2d910c8b25e75bf61b4933213696f7bc26f4a5a56d91b3ce31d9a063b6fd7bbd4633565b1d6ec + languageName: node + linkType: hard + +"micromark-extension-mdx-md@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-extension-mdx-md@npm:2.0.0" + dependencies: + micromark-util-types: ^2.0.0 + checksum: 7daf03372fd7faddf3f0ac87bdb0debb0bb770f33b586f72251e1072b222ceee75400ab6194c0e130dbf1e077369a5b627be6e9130d7a2e9e6b849f0d18ff246 + languageName: node + linkType: hard + +"micromark-extension-mdxjs-esm@npm:^3.0.0": + version: 3.0.0 + resolution: "micromark-extension-mdxjs-esm@npm:3.0.0" + dependencies: + "@types/estree": ^1.0.0 + devlop: ^1.0.0 + micromark-core-commonmark: ^2.0.0 + micromark-util-character: ^2.0.0 + micromark-util-events-to-acorn: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + unist-util-position-from-estree: ^2.0.0 + vfile-message: ^4.0.0 + checksum: fb33d850200afce567b95c90f2f7d42259bd33eea16154349e4fa77c3ec934f46c8e5c111acea16321dce3d9f85aaa4c49afe8b810e31b34effc11617aeee8f6 + languageName: node + linkType: hard + +"micromark-extension-mdxjs@npm:^3.0.0": + version: 3.0.0 + resolution: "micromark-extension-mdxjs@npm:3.0.0" + dependencies: + acorn: ^8.0.0 + acorn-jsx: ^5.0.0 + micromark-extension-mdx-expression: ^3.0.0 + micromark-extension-mdx-jsx: ^3.0.0 + micromark-extension-mdx-md: ^2.0.0 + micromark-extension-mdxjs-esm: ^3.0.0 + micromark-util-combine-extensions: ^2.0.0 + micromark-util-types: ^2.0.0 + checksum: 7da6f0fb0e1e0270a2f5ad257e7422cc16e68efa7b8214c63c9d55bc264cb872e9ca4ac9a71b9dfd13daf52e010f730bac316086f4340e4fcc6569ec699915bf + languageName: node + linkType: hard + "micromark-factory-destination@npm:^2.0.0": version: 2.0.1 resolution: "micromark-factory-destination@npm:2.0.1" @@ -15292,6 +19627,33 @@ __metadata: languageName: node linkType: hard +"micromark-factory-mdx-expression@npm:^2.0.0": + version: 2.0.3 + resolution: "micromark-factory-mdx-expression@npm:2.0.3" + dependencies: + "@types/estree": ^1.0.0 + devlop: ^1.0.0 + micromark-factory-space: ^2.0.0 + micromark-util-character: ^2.0.0 + micromark-util-events-to-acorn: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + unist-util-position-from-estree: ^2.0.0 + vfile-message: ^4.0.0 + checksum: f007987092a3bd00617f023d324caff10c63982e5125a3e3ff147baaf03f378e21c47306e2094b8c6480a726c57785c2175b4ffc3f3a6fde8be87e40fbdff068 + languageName: node + linkType: hard + +"micromark-factory-space@npm:^1.0.0": + version: 1.1.0 + resolution: "micromark-factory-space@npm:1.1.0" + dependencies: + micromark-util-character: ^1.0.0 + micromark-util-types: ^1.0.0 + checksum: b58435076b998a7e244259a4694eb83c78915581206b6e7fc07b34c6abd36a1726ade63df8972fbf6c8fa38eecb9074f4e17be8d53f942e3b3d23d1a0ecaa941 + languageName: node + linkType: hard + "micromark-factory-space@npm:^2.0.0": version: 2.0.1 resolution: "micromark-factory-space@npm:2.0.1" @@ -15326,6 +19688,16 @@ __metadata: languageName: node linkType: hard +"micromark-util-character@npm:^1.0.0, micromark-util-character@npm:^1.1.0": + version: 1.2.0 + resolution: "micromark-util-character@npm:1.2.0" + dependencies: + micromark-util-symbol: ^1.0.0 + micromark-util-types: ^1.0.0 + checksum: 089e79162a19b4a28731736246579ab7e9482ac93cd681c2bfca9983dcff659212ef158a66a5957e9d4b1dba957d1b87b565d85418a5b009f0294f1f07f2aaac + languageName: node + linkType: hard + "micromark-util-character@npm:^2.0.0": version: 2.1.1 resolution: "micromark-util-character@npm:2.1.1" @@ -15394,6 +19766,21 @@ __metadata: languageName: node linkType: hard +"micromark-util-events-to-acorn@npm:^2.0.0": + version: 2.0.3 + resolution: "micromark-util-events-to-acorn@npm:2.0.3" + dependencies: + "@types/estree": ^1.0.0 + "@types/unist": ^3.0.0 + devlop: ^1.0.0 + estree-util-visit: ^2.0.0 + micromark-util-symbol: ^2.0.0 + micromark-util-types: ^2.0.0 + vfile-message: ^4.0.0 + checksum: 8240f1aa072b3a2ec6df4fb55a0a19dd9f53923125a892da156e378b2af0333557f803f8da5228b03e5b1511c999701f0edbff9e483d00c5af5840f8466fb314 + languageName: node + linkType: hard + "micromark-util-html-tag-name@npm:^2.0.0": version: 2.0.1 resolution: "micromark-util-html-tag-name@npm:2.0.1" @@ -15442,6 +19829,13 @@ __metadata: languageName: node linkType: hard +"micromark-util-symbol@npm:^1.0.0, micromark-util-symbol@npm:^1.0.1": + version: 1.1.0 + resolution: "micromark-util-symbol@npm:1.1.0" + checksum: 02414a753b79f67ff3276b517eeac87913aea6c028f3e668a19ea0fc09d98aea9f93d6222a76ca783d20299af9e4b8e7c797fe516b766185dcc6e93290f11f88 + languageName: node + linkType: hard + "micromark-util-symbol@npm:^2.0.0": version: 2.0.1 resolution: "micromark-util-symbol@npm:2.0.1" @@ -15449,6 +19843,13 @@ __metadata: languageName: node linkType: hard +"micromark-util-types@npm:^1.0.0": + version: 1.1.0 + resolution: "micromark-util-types@npm:1.1.0" + checksum: b0ef2b4b9589f15aec2666690477a6a185536927ceb7aa55a0f46475852e012d75a1ab945187e5c7841969a842892164b15d58ff8316b8e0d6cc920cabd5ede7 + languageName: node + linkType: hard + "micromark-util-types@npm:^2.0.0": version: 2.0.2 resolution: "micromark-util-types@npm:2.0.2" @@ -15512,6 +19913,22 @@ __metadata: languageName: node linkType: hard +"mime-db@npm:~1.33.0": + version: 1.33.0 + resolution: "mime-db@npm:1.33.0" + checksum: 281a0772187c9b8f6096976cb193ac639c6007ac85acdbb8dc1617ed7b0f4777fa001d1b4f1b634532815e60717c84b2f280201d55677fb850c9d45015b50084 + languageName: node + linkType: hard + +"mime-types@npm:2.1.18": + version: 2.1.18 + resolution: "mime-types@npm:2.1.18" + dependencies: + mime-db: ~1.33.0 + checksum: 729265eff1e5a0e87cb7f869da742a610679585167d2f2ec997a7387fc6aedf8e5cad078e99b0164a927bdf3ace34fca27430d6487456ad090cba5594441ba43 + languageName: node + linkType: hard + "mime-types@npm:^2.1.12, mime-types@npm:^2.1.27, mime-types@npm:^2.1.31, mime-types@npm:^2.1.35, mime-types@npm:~2.1.17, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34": version: 2.1.35 resolution: "mime-types@npm:2.1.35" @@ -15521,7 +19938,7 @@ __metadata: languageName: node linkType: hard -"mime-types@npm:^3.0.0, mime-types@npm:^3.0.2": +"mime-types@npm:^3.0.0, mime-types@npm:^3.0.1, mime-types@npm:^3.0.2": version: 3.0.2 resolution: "mime-types@npm:3.0.2" dependencies: @@ -15562,6 +19979,13 @@ __metadata: languageName: node linkType: hard +"mimic-response@npm:^4.0.0": + version: 4.0.0 + resolution: "mimic-response@npm:4.0.0" + checksum: 33b804cc961efe206efdb1fca6a22540decdcfce6c14eb5c0c50e5ae9022267ab22ce8f5568b1f7247ba67500fe20d523d81e0e9f009b321ccd9d472e78d1850 + languageName: node + linkType: hard + "min-indent@npm:^1.0.0": version: 1.0.1 resolution: "min-indent@npm:1.0.1" @@ -15577,7 +20001,19 @@ __metadata: tapable: ^2.2.1 peerDependencies: webpack: ^5.0.0 - checksum: 4ec46ebdcb5dae4b1c012debca90fea27b1e8e7790d408154232d77d25f56f839e7b1ec5401a962d6356e7b9301c760d2ef62e1cb0d4d7b6ec8209f812733dda + checksum: 4ec46ebdcb5dae4b1c012debca90fea27b1e8e7790d408154232d77d25f56f839e7b1ec5401a962d6356e7b9301c760d2ef62e1cb0d4d7b6ec8209f812733dda + languageName: node + linkType: hard + +"mini-css-extract-plugin@npm:^2.9.2": + version: 2.10.0 + resolution: "mini-css-extract-plugin@npm:2.10.0" + dependencies: + schema-utils: ^4.0.0 + tapable: ^2.2.1 + peerDependencies: + webpack: ^5.0.0 + checksum: 53396dcf7ecf9706cc9d2a9fe5289e4c740b0f06978a9576b39fa973f54a69c7ccab33997a3bfa801608629c48d2c71dbcb735cf858780792bd4322779692c21 languageName: node linkType: hard @@ -15588,6 +20024,15 @@ __metadata: languageName: node linkType: hard +"minimatch@npm:3.1.2, minimatch@npm:^3.0.4, minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": + version: 3.1.2 + resolution: "minimatch@npm:3.1.2" + dependencies: + brace-expansion: ^1.1.7 + checksum: c154e566406683e7bcb746e000b84d74465b3a832c45d59912b9b55cd50dee66e5c4b1e5566dba26154040e51672f9aa450a9aef0c97cfc7336b78b7afb9540a + languageName: node + linkType: hard + "minimatch@npm:^10.1.1": version: 10.1.1 resolution: "minimatch@npm:10.1.1" @@ -15597,15 +20042,6 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^3.0.4, minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": - version: 3.1.2 - resolution: "minimatch@npm:3.1.2" - dependencies: - brace-expansion: ^1.1.7 - checksum: c154e566406683e7bcb746e000b84d74465b3a832c45d59912b9b55cd50dee66e5c4b1e5566dba26154040e51672f9aa450a9aef0c97cfc7336b78b7afb9540a - languageName: node - linkType: hard - "minimatch@npm:^5.0.1": version: 5.1.6 resolution: "minimatch@npm:5.1.6" @@ -15732,6 +20168,13 @@ __metadata: languageName: node linkType: hard +"mrmime@npm:^2.0.0": + version: 2.0.1 + resolution: "mrmime@npm:2.0.1" + checksum: 455a555009edb2ed6e587e0fcb5e41fcbf8f1dcca28242a57d054f02204ab198bed93ba9de75db06bd3447e8603bc74e10a22440ba99431fc4a751435fba35bf + languageName: node + linkType: hard + "ms@npm:2.0.0": version: 2.0.0 resolution: "ms@npm:2.0.0" @@ -15919,6 +20362,18 @@ __metadata: languageName: node linkType: hard +"node-emoji@npm:^2.1.0": + version: 2.2.0 + resolution: "node-emoji@npm:2.2.0" + dependencies: + "@sindresorhus/is": ^4.6.0 + char-regex: ^1.0.2 + emojilib: ^2.4.0 + skin-tone: ^2.0.0 + checksum: 9642bee0b8c5f2124580e6a2d4c5ec868987bc77b6ce3a335bbec8db677082cbe1a9b72c11aac60043396a8d36e0afad4bcc33d92105d103d2d1b6a59106219a + languageName: node + linkType: hard + "node-fetch-native@npm:^1.6.6": version: 1.6.7 resolution: "node-fetch-native@npm:1.6.7" @@ -16033,6 +20488,13 @@ __metadata: languageName: node linkType: hard +"normalize-url@npm:^8.0.0": + version: 8.1.1 + resolution: "normalize-url@npm:8.1.1" + checksum: 4fabd2fe2a2948384125282a4b8649ba5d470509c18576066c7aa8ee4809f5cb8a658861095dff4a04973bb5929f34c43b7ba192eb940a1ccd8324783a387060 + languageName: node + linkType: hard + "npm-run-path@npm:^4.0.1": version: 4.0.1 resolution: "npm-run-path@npm:4.0.1" @@ -16042,6 +20504,13 @@ __metadata: languageName: node linkType: hard +"nprogress@npm:^0.2.0": + version: 0.2.0 + resolution: "nprogress@npm:0.2.0" + checksum: 66b7bec5d563ecf2d1c3d2815e6d5eb74ed815eee8563e0afa63d3f185ab1b9cf2ddd97e1ded263b9995c5019d26d600320e849e50f3747984daa033744619dc + languageName: node + linkType: hard + "nth-check@npm:^1.0.2": version: 1.0.2 resolution: "nth-check@npm:1.0.2" @@ -16060,6 +20529,18 @@ __metadata: languageName: node linkType: hard +"null-loader@npm:^4.0.1": + version: 4.0.1 + resolution: "null-loader@npm:4.0.1" + dependencies: + loader-utils: ^2.0.0 + schema-utils: ^3.0.0 + peerDependencies: + webpack: ^4.0.0 || ^5.0.0 + checksum: eeb4c4dd2f8f41e46f5665e4500359109e95ec1028a178a60e0161984906572da7dd87644bcc3cb29f0125d77e2b2508fb4f3813cfb1c6604a15865beb4b987b + languageName: node + linkType: hard + "nwsapi@npm:^2.2.0": version: 2.2.23 resolution: "nwsapi@npm:2.2.23" @@ -16110,7 +20591,7 @@ __metadata: languageName: node linkType: hard -"object.assign@npm:^4.1.4, object.assign@npm:^4.1.7": +"object.assign@npm:^4.1.0, object.assign@npm:^4.1.4, object.assign@npm:^4.1.7": version: 4.1.7 resolution: "object.assign@npm:4.1.7" dependencies: @@ -16241,6 +20722,18 @@ __metadata: languageName: node linkType: hard +"open@npm:^10.0.3": + version: 10.2.0 + resolution: "open@npm:10.2.0" + dependencies: + default-browser: ^5.2.1 + define-lazy-prop: ^3.0.0 + is-inside-container: ^1.0.0 + wsl-utils: ^0.1.0 + checksum: 64e2e1fb1dc5ab82af06c990467237b8fd349b1b9ecc6324d12df337a005d039cec11f758abea148be68878ccd616977005682c48ef3c5c7ba48bd3e5d6a3dbb + languageName: node + linkType: hard + "open@npm:^8.0.9, open@npm:^8.4.0": version: 8.4.2 resolution: "open@npm:8.4.2" @@ -16252,6 +20745,15 @@ __metadata: languageName: node linkType: hard +"opener@npm:^1.5.2": + version: 1.5.2 + resolution: "opener@npm:1.5.2" + bin: + opener: bin/opener-bin.js + checksum: 33b620c0d53d5b883f2abc6687dd1c5fd394d270dbe33a6356f2d71e0a2ec85b100d5bac94694198ccf5c30d592da863b2292c5539009c715a9c80c697b4f6cc + languageName: node + linkType: hard + "optionator@npm:^0.8.1": version: 0.8.3 resolution: "optionator@npm:0.8.3" @@ -16298,6 +20800,13 @@ __metadata: languageName: node linkType: hard +"p-cancelable@npm:^3.0.0": + version: 3.0.0 + resolution: "p-cancelable@npm:3.0.0" + checksum: 2b5ae34218f9c2cf7a7c18e5d9a726ef9b165ef07e6c959f6738371509e747334b5f78f3bcdeb03d8a12dcb978faf641fd87eb21486ed7d36fb823b8ddef3219 + languageName: node + linkType: hard + "p-finally@npm:^1.0.0": version: 1.0.0 resolution: "p-finally@npm:1.0.0" @@ -16323,6 +20832,15 @@ __metadata: languageName: node linkType: hard +"p-limit@npm:^4.0.0": + version: 4.0.0 + resolution: "p-limit@npm:4.0.0" + dependencies: + yocto-queue: ^1.0.0 + checksum: 01d9d70695187788f984226e16c903475ec6a947ee7b21948d6f597bed788e3112cc7ec2e171c1d37125057a5f45f3da21d8653e04a3a793589e12e9e80e756b + languageName: node + linkType: hard + "p-locate@npm:^3.0.0": version: 3.0.0 resolution: "p-locate@npm:3.0.0" @@ -16350,6 +20868,24 @@ __metadata: languageName: node linkType: hard +"p-locate@npm:^6.0.0": + version: 6.0.0 + resolution: "p-locate@npm:6.0.0" + dependencies: + p-limit: ^4.0.0 + checksum: 2bfe5234efa5e7a4e74b30a5479a193fdd9236f8f6b4d2f3f69e3d286d9a7d7ab0c118a2a50142efcf4e41625def635bd9332d6cbf9cc65d85eb0718c579ab38 + languageName: node + linkType: hard + +"p-map@npm:^4.0.0": + version: 4.0.0 + resolution: "p-map@npm:4.0.0" + dependencies: + aggregate-error: ^3.0.0 + checksum: cb0ab21ec0f32ddffd31dfc250e3afa61e103ef43d957cc45497afe37513634589316de4eb88abdfd969fe6410c22c0b93ab24328833b8eb1ccc087fc0442a1c + languageName: node + linkType: hard + "p-map@npm:^7.0.2": version: 7.0.4 resolution: "p-map@npm:7.0.4" @@ -16357,7 +20893,7 @@ __metadata: languageName: node linkType: hard -"p-queue@npm:^6": +"p-queue@npm:^6, p-queue@npm:^6.6.2": version: 6.6.2 resolution: "p-queue@npm:6.6.2" dependencies: @@ -16377,6 +20913,17 @@ __metadata: languageName: node linkType: hard +"p-retry@npm:^6.2.0": + version: 6.2.1 + resolution: "p-retry@npm:6.2.1" + dependencies: + "@types/retry": 0.12.2 + is-network-error: ^1.0.0 + retry: ^0.13.1 + checksum: 73acd269544b1359b7f2aa5f907f6f8cd4947c596bc43cc25fecce2678e2f190095179407eb874f0e09fc5956ae7952c39ebb08c3d9334f59d41ae0b2d73ee6b + languageName: node + linkType: hard + "p-timeout@npm:^3.2.0": version: 3.2.0 resolution: "p-timeout@npm:3.2.0" @@ -16400,6 +20947,18 @@ __metadata: languageName: node linkType: hard +"package-json@npm:^8.1.0": + version: 8.1.1 + resolution: "package-json@npm:8.1.1" + dependencies: + got: ^12.1.0 + registry-auth-token: ^5.0.1 + registry-url: ^6.0.0 + semver: ^7.3.7 + checksum: 28bec6f42bf9fba66b7c8fea07576fc23d08ec7923433f7835d6cd8654e72169d74f9738b3785107d18a476ae76712e0daeb1dddcd6930e69f9e4b47eba7c0ca + languageName: node + linkType: hard + "pako@npm:^1.0.10, pako@npm:^1.0.11, pako@npm:^1.0.6": version: 1.0.11 resolution: "pako@npm:1.0.11" @@ -16453,6 +21012,23 @@ __metadata: languageName: node linkType: hard +"parse-numeric-range@npm:^1.3.0": + version: 1.3.0 + resolution: "parse-numeric-range@npm:1.3.0" + checksum: 289ca126d5b8ace7325b199218de198014f58ea6895ccc88a5247491d07f0143bf047f80b4a31784f1ca8911762278d7d6ecb90a31dfae31da91cc1a2524c8ce + languageName: node + linkType: hard + +"parse5-htmlparser2-tree-adapter@npm:^7.0.0": + version: 7.1.0 + resolution: "parse5-htmlparser2-tree-adapter@npm:7.1.0" + dependencies: + domhandler: ^5.0.3 + parse5: ^7.0.0 + checksum: 98326fc5443e2149e10695adbfd0b0b3383c54398799f858b4ac2914adb199af8fcc90c2143aa5f7fd5f9482338f26ef253b468722f34d50bb215ec075d89fe9 + languageName: node + linkType: hard + "parse5@npm:6.0.1": version: 6.0.1 resolution: "parse5@npm:6.0.1" @@ -16460,6 +21036,15 @@ __metadata: languageName: node linkType: hard +"parse5@npm:^7.0.0": + version: 7.3.0 + resolution: "parse5@npm:7.3.0" + dependencies: + entities: ^6.0.0 + checksum: ffd040c4695d93f0bc370e3d6d75c1b352178514af41be7afa212475ea5cead1d6e377cd9d4cec6a5e2bcf497ca50daf9e0088eadaa37dbc271f60def08fdfcd + languageName: node + linkType: hard + "parseurl@npm:^1.3.3, parseurl@npm:~1.3.2, parseurl@npm:~1.3.3": version: 1.3.3 resolution: "parseurl@npm:1.3.3" @@ -16501,6 +21086,13 @@ __metadata: languageName: node linkType: hard +"path-exists@npm:^5.0.0": + version: 5.0.0 + resolution: "path-exists@npm:5.0.0" + checksum: 8ca842868cab09423994596eb2c5ec2a971c17d1a3cb36dbf060592c730c725cd524b9067d7d2a1e031fef9ba7bd2ac6dc5ec9fb92aa693265f7be3987045254 + languageName: node + linkType: hard + "path-is-absolute@npm:^1.0.0": version: 1.0.1 resolution: "path-is-absolute@npm:1.0.1" @@ -16508,6 +21100,13 @@ __metadata: languageName: node linkType: hard +"path-is-inside@npm:1.0.2": + version: 1.0.2 + resolution: "path-is-inside@npm:1.0.2" + checksum: 0b5b6c92d3018b82afb1f74fe6de6338c4c654de4a96123cb343f2b747d5606590ac0c890f956ed38220a4ab59baddfd7b713d78a62d240b20b14ab801fa02cb + languageName: node + linkType: hard + "path-key@npm:^3.0.0, path-key@npm:^3.1.0": version: 3.1.1 resolution: "path-key@npm:3.1.1" @@ -16532,6 +21131,13 @@ __metadata: languageName: node linkType: hard +"path-to-regexp@npm:3.3.0": + version: 3.3.0 + resolution: "path-to-regexp@npm:3.3.0" + checksum: bb249d08804f7961dd44fb175466c900b893c56e909db8e2a66ec12b9d9a964af269eb7a50892c933f52b47315953dfdb4279639fbce20977c3625a9ef3055fe + languageName: node + linkType: hard + "path-to-regexp@npm:^1.7.0": version: 1.9.0 resolution: "path-to-regexp@npm:1.9.0" @@ -16689,6 +21295,15 @@ __metadata: languageName: node linkType: hard +"pkg-dir@npm:^7.0.0": + version: 7.0.0 + resolution: "pkg-dir@npm:7.0.0" + dependencies: + find-up: ^6.3.0 + checksum: 94298b20a446bfbbd66604474de8a0cdd3b8d251225170970f15d9646f633e056c80520dd5b4c1d1050c9fed8f6a9e5054b141c93806439452efe72e57562c03 + languageName: node + linkType: hard + "pkg-types@npm:^2.2.0, pkg-types@npm:^2.3.0": version: 2.3.0 resolution: "pkg-types@npm:2.3.0" @@ -16709,6 +21324,20 @@ __metadata: languageName: node linkType: hard +"pkijs@npm:^3.3.3": + version: 3.3.3 + resolution: "pkijs@npm:3.3.3" + dependencies: + "@noble/hashes": 1.4.0 + asn1js: ^3.0.6 + bytestreamjs: ^2.0.1 + pvtsutils: ^1.3.6 + pvutils: ^1.1.3 + tslib: ^2.8.1 + checksum: b1b12435af6f7150b2c66988b719c8e514bf66e241f1ffb76fdfb4fd9090192b296147ae84a27e0bf1ebd809ceec156ae3157f388dc5b90a6c2979d7a7f6ae15 + languageName: node + linkType: hard + "possible-typed-array-names@npm:^1.0.0": version: 1.1.0 resolution: "possible-typed-array-names@npm:1.1.0" @@ -16727,6 +21356,17 @@ __metadata: languageName: node linkType: hard +"postcss-attribute-case-insensitive@npm:^7.0.1": + version: 7.0.1 + resolution: "postcss-attribute-case-insensitive@npm:7.0.1" + dependencies: + postcss-selector-parser: ^7.0.0 + peerDependencies: + postcss: ^8.4 + checksum: 18829dfc6dd2f6b1ca82afa8555f07ec8ac5687fe95612e353aa601b842bdec05ca78fc96016dba2b7d32607b31e085e5087fda00e1e0dfdc6c2a1b07b1b15c2 + languageName: node + linkType: hard + "postcss-browser-comments@npm:^4": version: 4.0.0 resolution: "postcss-browser-comments@npm:4.0.0" @@ -16749,6 +21389,18 @@ __metadata: languageName: node linkType: hard +"postcss-calc@npm:^9.0.1": + version: 9.0.1 + resolution: "postcss-calc@npm:9.0.1" + dependencies: + postcss-selector-parser: ^6.0.11 + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.2.2 + checksum: 7327ed83bfec544ab8b3e38353baa72ff6d04378b856db4ad82dbd68ce0b73668867ef182b5d4025f9dd9aa9c64aacc50cd1bd9db8d8b51ccc4cb97866b9d72b + languageName: node + linkType: hard + "postcss-clamp@npm:^4.1.0": version: 4.1.0 resolution: "postcss-clamp@npm:4.1.0" @@ -16771,6 +21423,33 @@ __metadata: languageName: node linkType: hard +"postcss-color-functional-notation@npm:^7.0.12": + version: 7.0.12 + resolution: "postcss-color-functional-notation@npm:7.0.12" + dependencies: + "@csstools/css-color-parser": ^3.1.0 + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + "@csstools/postcss-progressive-custom-properties": ^4.2.1 + "@csstools/utilities": ^2.0.0 + peerDependencies: + postcss: ^8.4 + checksum: c3f59571330defde7c95256dbc2756ffd298072a6b167eb6751efb2f97ac267c081d7313556e3a4615cff8a46202f3c149bb2a456326805ca0cba5173faf5aad + languageName: node + linkType: hard + +"postcss-color-hex-alpha@npm:^10.0.0": + version: 10.0.0 + resolution: "postcss-color-hex-alpha@npm:10.0.0" + dependencies: + "@csstools/utilities": ^2.0.0 + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.4 + checksum: 2dbbd66d76522c7d281c292589360f21806b6dd31a582484e7e4a848e5244d645d5c5e1b6c6219dd5fb7333808cd94a27dd0d2e1db093d043668ed7b42db59ad + languageName: node + linkType: hard + "postcss-color-hex-alpha@npm:^8.0.4": version: 8.0.4 resolution: "postcss-color-hex-alpha@npm:8.0.4" @@ -16782,6 +21461,18 @@ __metadata: languageName: node linkType: hard +"postcss-color-rebeccapurple@npm:^10.0.0": + version: 10.0.0 + resolution: "postcss-color-rebeccapurple@npm:10.0.0" + dependencies: + "@csstools/utilities": ^2.0.0 + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.4 + checksum: 8ca0ee2b6b45ff62abdfc9b6757d8832d398c2e47dd705759485b685f544eaed81ec00f050a1bad67ffb5e6243332085a09807d47526ce3b43456b027119e0ae + languageName: node + linkType: hard + "postcss-color-rebeccapurple@npm:^7.1.1": version: 7.1.1 resolution: "postcss-color-rebeccapurple@npm:7.1.1" @@ -16807,6 +21498,20 @@ __metadata: languageName: node linkType: hard +"postcss-colormin@npm:^6.1.0": + version: 6.1.0 + resolution: "postcss-colormin@npm:6.1.0" + dependencies: + browserslist: ^4.23.0 + caniuse-api: ^3.0.0 + colord: ^2.9.3 + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.4.31 + checksum: 55a1525de345d953bc7f32ecaa5ee6275ef0277c27d1f97ff06a1bd1a2fedf7f254e36dc1500621f1df20c25a6d2485a74a0b527d8ff74eb90726c76efe2ac8e + languageName: node + linkType: hard + "postcss-convert-values@npm:^5.1.3": version: 5.1.3 resolution: "postcss-convert-values@npm:5.1.3" @@ -16819,6 +21524,32 @@ __metadata: languageName: node linkType: hard +"postcss-convert-values@npm:^6.1.0": + version: 6.1.0 + resolution: "postcss-convert-values@npm:6.1.0" + dependencies: + browserslist: ^4.23.0 + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.4.31 + checksum: 43e9f66af9bdec3c76695f9dde36885abc01f662c370c490b45d895459caab2c5792f906f3ddad107129133e41485a65634da7f699eef916a636e47f6a37a299 + languageName: node + linkType: hard + +"postcss-custom-media@npm:^11.0.6": + version: 11.0.6 + resolution: "postcss-custom-media@npm:11.0.6" + dependencies: + "@csstools/cascade-layer-name-parser": ^2.0.5 + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + "@csstools/media-query-list-parser": ^4.0.3 + peerDependencies: + postcss: ^8.4 + checksum: 3b8ab5eb6d80cf9dd0b74acf69530f73009d860509d820fc5349894a10c2abd08eb1ff77f90c59ee51aebf422fe09d4093ece8d15f652f771ab0fcfd03a42417 + languageName: node + linkType: hard + "postcss-custom-media@npm:^8.0.2": version: 8.0.2 resolution: "postcss-custom-media@npm:8.0.2" @@ -16841,6 +21572,21 @@ __metadata: languageName: node linkType: hard +"postcss-custom-properties@npm:^14.0.6": + version: 14.0.6 + resolution: "postcss-custom-properties@npm:14.0.6" + dependencies: + "@csstools/cascade-layer-name-parser": ^2.0.5 + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + "@csstools/utilities": ^2.0.0 + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.4 + checksum: f78999e036e8406efcbbd2d7dec599910de88a32a3e829b0c2e78abf6d8944a79fe61fb2cc2ecd07bb96a392249846c363af40c5dc7d3ab8c36606a79c324a28 + languageName: node + linkType: hard + "postcss-custom-selectors@npm:^6.0.3": version: 6.0.3 resolution: "postcss-custom-selectors@npm:6.0.3" @@ -16852,6 +21598,20 @@ __metadata: languageName: node linkType: hard +"postcss-custom-selectors@npm:^8.0.5": + version: 8.0.5 + resolution: "postcss-custom-selectors@npm:8.0.5" + dependencies: + "@csstools/cascade-layer-name-parser": ^2.0.5 + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + postcss-selector-parser: ^7.0.0 + peerDependencies: + postcss: ^8.4 + checksum: 191cfe62ad3eaf3d8bff75ed461baebbb3b9a52de9c1c75bded61da4ed2302d7c53c457e9febfa7cffc9a1fb7f6ed98cab8c4b2a071a1097e487e0117018e6cf + languageName: node + linkType: hard + "postcss-dir-pseudo-class@npm:^6.0.5": version: 6.0.5 resolution: "postcss-dir-pseudo-class@npm:6.0.5" @@ -16863,6 +21623,17 @@ __metadata: languageName: node linkType: hard +"postcss-dir-pseudo-class@npm:^9.0.1": + version: 9.0.1 + resolution: "postcss-dir-pseudo-class@npm:9.0.1" + dependencies: + postcss-selector-parser: ^7.0.0 + peerDependencies: + postcss: ^8.4 + checksum: 7f6212fe7f2a83e95d85df14208df3edb75b6b8f89ad865fdfbd1abf5765b6649ff46bb7ff56f7788ff8cfe60546ff305cc2fd2f9b1f9e1647a4386507714070 + languageName: node + linkType: hard + "postcss-discard-comments@npm:^5.1.2": version: 5.1.2 resolution: "postcss-discard-comments@npm:5.1.2" @@ -16872,6 +21643,15 @@ __metadata: languageName: node linkType: hard +"postcss-discard-comments@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-discard-comments@npm:6.0.2" + peerDependencies: + postcss: ^8.4.31 + checksum: c1731ccc8d1e3d910412a61395988d3033365e6532d9e5432ad7c74add8c9dcb0af0c03d4e901bf0d2b59ea4e7297a0c77a547ff2ed1b1cc065559cc0de43b4e + languageName: node + linkType: hard + "postcss-discard-duplicates@npm:^5.1.0": version: 5.1.0 resolution: "postcss-discard-duplicates@npm:5.1.0" @@ -16881,6 +21661,15 @@ __metadata: languageName: node linkType: hard +"postcss-discard-duplicates@npm:^6.0.3": + version: 6.0.3 + resolution: "postcss-discard-duplicates@npm:6.0.3" + peerDependencies: + postcss: ^8.4.31 + checksum: 308e3fb84c35e4703532de1efa5d6e8444cc5f167d0e40f42d7ea3fa3a37d9d636fd10729847d078e0c303eee16f8548d14b6f88a3fce4e38a2b452648465175 + languageName: node + linkType: hard + "postcss-discard-empty@npm:^5.1.1": version: 5.1.1 resolution: "postcss-discard-empty@npm:5.1.1" @@ -16890,6 +21679,15 @@ __metadata: languageName: node linkType: hard +"postcss-discard-empty@npm:^6.0.3": + version: 6.0.3 + resolution: "postcss-discard-empty@npm:6.0.3" + peerDependencies: + postcss: ^8.4.31 + checksum: bad305572faa066026a295faab37e718cee096589ab827b19c990c55620b2b2a1ce9f0145212651737a66086db01b2676c1927bbb8408c5f9cb42686d5959f00 + languageName: node + linkType: hard + "postcss-discard-overridden@npm:^5.1.0": version: 5.1.0 resolution: "postcss-discard-overridden@npm:5.1.0" @@ -16899,6 +21697,26 @@ __metadata: languageName: node linkType: hard +"postcss-discard-overridden@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-discard-overridden@npm:6.0.2" + peerDependencies: + postcss: ^8.4.31 + checksum: a38e0fe7a36f83cb9b73c1ba9ee2a48cf93c69ec0ea5753935824ffb71e958e58ae0393171c0f3d0014a397469d09bbb0d56bb5ab80f0280722967e2e273aebb + languageName: node + linkType: hard + +"postcss-discard-unused@npm:^6.0.5": + version: 6.0.5 + resolution: "postcss-discard-unused@npm:6.0.5" + dependencies: + postcss-selector-parser: ^6.0.16 + peerDependencies: + postcss: ^8.4.31 + checksum: 7962640773240186de38125f142a6555b7f9b2493c4968e0f0b11c6629b2bf43ac70b9fc4ee78aa732d82670ad8bf802b2febc9a9864b022eb68530eded26836 + languageName: node + linkType: hard + "postcss-double-position-gradients@npm:^3.1.2": version: 3.1.2 resolution: "postcss-double-position-gradients@npm:3.1.2" @@ -16911,6 +21729,19 @@ __metadata: languageName: node linkType: hard +"postcss-double-position-gradients@npm:^6.0.4": + version: 6.0.4 + resolution: "postcss-double-position-gradients@npm:6.0.4" + dependencies: + "@csstools/postcss-progressive-custom-properties": ^4.2.1 + "@csstools/utilities": ^2.0.0 + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.4 + checksum: 2840202fd819b48f713c63e1bca5e3f6b88ac5374cf2e4ebf6fabad6d5493685f9a3cde6f890ca73f978a7f5cde5ba4b6ec02659715a0b035e9be1063b74fb1f + languageName: node + linkType: hard + "postcss-env-function@npm:^4.0.6": version: 4.0.6 resolution: "postcss-env-function@npm:4.0.6" @@ -16931,6 +21762,17 @@ __metadata: languageName: node linkType: hard +"postcss-focus-visible@npm:^10.0.1": + version: 10.0.1 + resolution: "postcss-focus-visible@npm:10.0.1" + dependencies: + postcss-selector-parser: ^7.0.0 + peerDependencies: + postcss: ^8.4 + checksum: 47c038ccf139bad6a4c12cf59c5ac78acbac96ae0517ae08d5db676680d585ae7943e22328bd0d31876d6bacc24e4b717b5f809d26218d76989f7b9a44369793 + languageName: node + linkType: hard + "postcss-focus-visible@npm:^6.0.4": version: 6.0.4 resolution: "postcss-focus-visible@npm:6.0.4" @@ -16942,14 +21784,25 @@ __metadata: languageName: node linkType: hard -"postcss-focus-within@npm:^5.0.4": - version: 5.0.4 - resolution: "postcss-focus-within@npm:5.0.4" +"postcss-focus-within@npm:^5.0.4": + version: 5.0.4 + resolution: "postcss-focus-within@npm:5.0.4" + dependencies: + postcss-selector-parser: ^6.0.9 + peerDependencies: + postcss: ^8.4 + checksum: f23d8ab757345a6deaa807d76e10c88caf4b771c38b60e1593b24aee161c503b5823620e89302226a6ae5e7afdb6ac31809241291912e4176eb594a7ddcc9521 + languageName: node + linkType: hard + +"postcss-focus-within@npm:^9.0.1": + version: 9.0.1 + resolution: "postcss-focus-within@npm:9.0.1" dependencies: - postcss-selector-parser: ^6.0.9 + postcss-selector-parser: ^7.0.0 peerDependencies: postcss: ^8.4 - checksum: f23d8ab757345a6deaa807d76e10c88caf4b771c38b60e1593b24aee161c503b5823620e89302226a6ae5e7afdb6ac31809241291912e4176eb594a7ddcc9521 + checksum: ca953bf566605c6519f5318a5a4886f8f0698798ba96d505c287cc0397d90a80246de948af354592a680615667e553c3fb67e88d9f55bdf630dab67b0fc0ceaa languageName: node linkType: hard @@ -16971,6 +21824,15 @@ __metadata: languageName: node linkType: hard +"postcss-gap-properties@npm:^6.0.0": + version: 6.0.0 + resolution: "postcss-gap-properties@npm:6.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 8fa8a208fe254ddfcb0442072a6232576efa1fc3deea917be6d3a0c25dfcb855cc6806572e42a098aa0276a5ad3917f19b269409f5ce1f22d233c0072d72f823 + languageName: node + linkType: hard + "postcss-image-set-function@npm:^4.0.7": version: 4.0.7 resolution: "postcss-image-set-function@npm:4.0.7" @@ -16982,6 +21844,18 @@ __metadata: languageName: node linkType: hard +"postcss-image-set-function@npm:^7.0.0": + version: 7.0.0 + resolution: "postcss-image-set-function@npm:7.0.0" + dependencies: + "@csstools/utilities": ^2.0.0 + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.4 + checksum: 328946f3f258c230ac50f2f54dc43ac89f21b1afe42e2828fa20bfd19692a1198e439becabe9dfb64de50932c6ef987a8b2b5ea9398ae7ca813afb4f7e595be7 + languageName: node + linkType: hard + "postcss-import@npm:^15.1.0": version: 15.1.0 resolution: "postcss-import@npm:15.1.0" @@ -17027,6 +21901,21 @@ __metadata: languageName: node linkType: hard +"postcss-lab-function@npm:^7.0.12": + version: 7.0.12 + resolution: "postcss-lab-function@npm:7.0.12" + dependencies: + "@csstools/css-color-parser": ^3.1.0 + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + "@csstools/postcss-progressive-custom-properties": ^4.2.1 + "@csstools/utilities": ^2.0.0 + peerDependencies: + postcss: ^8.4 + checksum: 4f16254449b2095b143e16ecf4fcae05e461ccd76786059a643e4666589f5793b3aed7d2103bfb00523e40d60a7c77ead563cfbaa39167c69a35e454bbed7ef8 + languageName: node + linkType: hard + "postcss-load-config@npm:^4.0.2 || ^5.0 || ^6.0": version: 6.0.1 resolution: "postcss-load-config@npm:6.0.1" @@ -17064,6 +21953,20 @@ __metadata: languageName: node linkType: hard +"postcss-loader@npm:^7.3.4": + version: 7.3.4 + resolution: "postcss-loader@npm:7.3.4" + dependencies: + cosmiconfig: ^8.3.5 + jiti: ^1.20.0 + semver: ^7.5.4 + peerDependencies: + postcss: ^7.0.0 || ^8.0.1 + webpack: ^5.0.0 + checksum: f109eb266580eb296441a1ae057f93629b9b79ad962bdd3fc134417180431606a5419b6f5848c31e6d92c818e71fe96e4335a85cc5332c2f7b14e2869951e5b3 + languageName: node + linkType: hard + "postcss-logical@npm:^5.0.4": version: 5.0.4 resolution: "postcss-logical@npm:5.0.4" @@ -17073,6 +21976,17 @@ __metadata: languageName: node linkType: hard +"postcss-logical@npm:^8.1.0": + version: 8.1.0 + resolution: "postcss-logical@npm:8.1.0" + dependencies: + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.4 + checksum: 7db1e8c9f9c1ec9dc8cef56830ac3686766629cc7e28c0494b6e0f3699979f18c11225a39c37210cf81be4491adaa6bdbc394429d7e050f2d03e5845ef6608f9 + languageName: node + linkType: hard + "postcss-media-minmax@npm:^5.0.0": version: 5.0.0 resolution: "postcss-media-minmax@npm:5.0.0" @@ -17082,6 +21996,18 @@ __metadata: languageName: node linkType: hard +"postcss-merge-idents@npm:^6.0.3": + version: 6.0.3 + resolution: "postcss-merge-idents@npm:6.0.3" + dependencies: + cssnano-utils: ^4.0.2 + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.4.31 + checksum: b45780d6d103b8e45a580032747ee6e1842f81863672341a6b4961397e243ca896217bf1f3ee732376a766207d5f610ba8924cf08cf6d5bbd4b093133fd05d70 + languageName: node + linkType: hard + "postcss-merge-longhand@npm:^5.1.7": version: 5.1.7 resolution: "postcss-merge-longhand@npm:5.1.7" @@ -17094,6 +22020,18 @@ __metadata: languageName: node linkType: hard +"postcss-merge-longhand@npm:^6.0.5": + version: 6.0.5 + resolution: "postcss-merge-longhand@npm:6.0.5" + dependencies: + postcss-value-parser: ^4.2.0 + stylehacks: ^6.1.1 + peerDependencies: + postcss: ^8.4.31 + checksum: 9ae5acf47dc0c1f494684ae55672d55bba7f5ee11c9c0f266aabd7c798e9f7394c6096363cd95685fd21ef088740389121a317772cf523ca22c915009bca2617 + languageName: node + linkType: hard + "postcss-merge-rules@npm:^5.1.4": version: 5.1.4 resolution: "postcss-merge-rules@npm:5.1.4" @@ -17108,6 +22046,20 @@ __metadata: languageName: node linkType: hard +"postcss-merge-rules@npm:^6.1.1": + version: 6.1.1 + resolution: "postcss-merge-rules@npm:6.1.1" + dependencies: + browserslist: ^4.23.0 + caniuse-api: ^3.0.0 + cssnano-utils: ^4.0.2 + postcss-selector-parser: ^6.0.16 + peerDependencies: + postcss: ^8.4.31 + checksum: 43f60a1c88806491cf752ae7871676de0e7a2a9d6d2fc6bc894068cc35a910a63d30f7c7d79545e0926c8b3a9ec583e5e8357203c40b5bad5ff58133b0c900f6 + languageName: node + linkType: hard + "postcss-minify-font-values@npm:^5.1.0": version: 5.1.0 resolution: "postcss-minify-font-values@npm:5.1.0" @@ -17119,6 +22071,17 @@ __metadata: languageName: node linkType: hard +"postcss-minify-font-values@npm:^6.1.0": + version: 6.1.0 + resolution: "postcss-minify-font-values@npm:6.1.0" + dependencies: + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.4.31 + checksum: 985e4dd2f89220a4442a822aad7dff016ab58a9dbb7bbca9d01c2d07d5a1e7d8c02e1c6e836abb4c9b4e825b4b80d99ee1f5899e74bf0d969095037738e6e452 + languageName: node + linkType: hard + "postcss-minify-gradients@npm:^5.1.1": version: 5.1.1 resolution: "postcss-minify-gradients@npm:5.1.1" @@ -17132,6 +22095,19 @@ __metadata: languageName: node linkType: hard +"postcss-minify-gradients@npm:^6.0.3": + version: 6.0.3 + resolution: "postcss-minify-gradients@npm:6.0.3" + dependencies: + colord: ^2.9.3 + cssnano-utils: ^4.0.2 + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.4.31 + checksum: 89b95088c3830f829f6d4636d1be4d4f13300bf9f1577c48c25169c81e11ec0026760b9abb32112b95d2c622f09d3b737f4d2975a7842927ccb567e1002ef7b3 + languageName: node + linkType: hard + "postcss-minify-params@npm:^5.1.4": version: 5.1.4 resolution: "postcss-minify-params@npm:5.1.4" @@ -17145,6 +22121,19 @@ __metadata: languageName: node linkType: hard +"postcss-minify-params@npm:^6.1.0": + version: 6.1.0 + resolution: "postcss-minify-params@npm:6.1.0" + dependencies: + browserslist: ^4.23.0 + cssnano-utils: ^4.0.2 + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.4.31 + checksum: 1e1cc3057d9bcc532c70e40628e96e3aea0081d8072dffe983a270a8cd59c03ac585e57d036b70e43d4ee725f274a05a6a8efac5a715f448284e115c13f82a46 + languageName: node + linkType: hard + "postcss-minify-selectors@npm:^5.2.1": version: 5.2.1 resolution: "postcss-minify-selectors@npm:5.2.1" @@ -17156,6 +22145,17 @@ __metadata: languageName: node linkType: hard +"postcss-minify-selectors@npm:^6.0.4": + version: 6.0.4 + resolution: "postcss-minify-selectors@npm:6.0.4" + dependencies: + postcss-selector-parser: ^6.0.16 + peerDependencies: + postcss: ^8.4.31 + checksum: 150221a84422ca7627c67ee691ee51e0fe2c3583c8108801e9fc93d3be8b538c2eb04fcfdc908270d7eeaeaf01594a20b81311690a873efccb8a23aeafe1c354 + languageName: node + linkType: hard + "postcss-modules-extract-imports@npm:^3.1.0": version: 3.1.0 resolution: "postcss-modules-extract-imports@npm:3.1.0" @@ -17241,6 +22241,19 @@ __metadata: languageName: node linkType: hard +"postcss-nesting@npm:^13.0.2": + version: 13.0.2 + resolution: "postcss-nesting@npm:13.0.2" + dependencies: + "@csstools/selector-resolve-nested": ^3.1.0 + "@csstools/selector-specificity": ^5.0.0 + postcss-selector-parser: ^7.0.0 + peerDependencies: + postcss: ^8.4 + checksum: fce488a2e77d9a8183a4e014caf047e41cb2422c07de1d49a092734fc90feeb8ced21090e3e284cfb2956afdba73e4a3547065ede228b209003bac5e1de62f0a + languageName: node + linkType: hard + "postcss-normalize-charset@npm:^5.1.0": version: 5.1.0 resolution: "postcss-normalize-charset@npm:5.1.0" @@ -17250,6 +22263,15 @@ __metadata: languageName: node linkType: hard +"postcss-normalize-charset@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-normalize-charset@npm:6.0.2" + peerDependencies: + postcss: ^8.4.31 + checksum: 5b8aeb17d61578a8656571cd5d5eefa8d4ee7126a99a41fdd322078002a06f2ae96f649197b9c01067a5f3e38a2e4b03e0e3fda5a0ec9e3d7ad056211ce86156 + languageName: node + linkType: hard + "postcss-normalize-display-values@npm:^5.1.0": version: 5.1.0 resolution: "postcss-normalize-display-values@npm:5.1.0" @@ -17261,6 +22283,17 @@ __metadata: languageName: node linkType: hard +"postcss-normalize-display-values@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-normalize-display-values@npm:6.0.2" + dependencies: + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.4.31 + checksum: da30a9394b0e4a269ccad8d240693a6cd564bcc60e24db67caee00f70ddfbc070ad76faed64c32e6eec9ed02e92565488b7879d4fd6c40d877c290eadbb0bb28 + languageName: node + linkType: hard + "postcss-normalize-positions@npm:^5.1.1": version: 5.1.1 resolution: "postcss-normalize-positions@npm:5.1.1" @@ -17272,6 +22305,17 @@ __metadata: languageName: node linkType: hard +"postcss-normalize-positions@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-normalize-positions@npm:6.0.2" + dependencies: + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.4.31 + checksum: 44fb77583fae4d71b76e38226cf770570876bcf5af6940dc9aeac7a7e2252896b361e0249044766cff8dad445f925378f06a005d6541597573c20e599a62b516 + languageName: node + linkType: hard + "postcss-normalize-repeat-style@npm:^5.1.1": version: 5.1.1 resolution: "postcss-normalize-repeat-style@npm:5.1.1" @@ -17283,6 +22327,17 @@ __metadata: languageName: node linkType: hard +"postcss-normalize-repeat-style@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-normalize-repeat-style@npm:6.0.2" + dependencies: + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.4.31 + checksum: bebdac63bec6777ead3e265fc12527b261cf8d0da1b7f0abb12bda86fd53b7058e4afe392210ac74dac012e413bb1c2a46a1138c89f82b8bf70b81711f620f8c + languageName: node + linkType: hard + "postcss-normalize-string@npm:^5.1.0": version: 5.1.0 resolution: "postcss-normalize-string@npm:5.1.0" @@ -17294,6 +22349,17 @@ __metadata: languageName: node linkType: hard +"postcss-normalize-string@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-normalize-string@npm:6.0.2" + dependencies: + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.4.31 + checksum: 5e8e253c528b542accafc142846fb33643c342a787c86e5b68c6287c7d8f63c5ae7d4d3fc28e3daf80821cc26a91add135e58bdd62ff9c735fca65d994898c7d + languageName: node + linkType: hard + "postcss-normalize-timing-functions@npm:^5.1.0": version: 5.1.0 resolution: "postcss-normalize-timing-functions@npm:5.1.0" @@ -17305,6 +22371,17 @@ __metadata: languageName: node linkType: hard +"postcss-normalize-timing-functions@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-normalize-timing-functions@npm:6.0.2" + dependencies: + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.4.31 + checksum: 1970f5aad04be11f99d51c59e27debb6fd7b49d0fa4a8879062b42c82113f8e520a284448727add3b54de85deefb8bd5fe554f618406586e9ad8fc9d060609f1 + languageName: node + linkType: hard + "postcss-normalize-unicode@npm:^5.1.1": version: 5.1.1 resolution: "postcss-normalize-unicode@npm:5.1.1" @@ -17317,6 +22394,18 @@ __metadata: languageName: node linkType: hard +"postcss-normalize-unicode@npm:^6.1.0": + version: 6.1.0 + resolution: "postcss-normalize-unicode@npm:6.1.0" + dependencies: + browserslist: ^4.23.0 + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.4.31 + checksum: 69ef35d06242061f0c504c128b83752e0f8daa30ebb26734de7d090460910be0b2efd8b17b1d64c3c85b95831a041faad9ad0aaba80e239406a79cfad3d63568 + languageName: node + linkType: hard + "postcss-normalize-url@npm:^5.1.0": version: 5.1.0 resolution: "postcss-normalize-url@npm:5.1.0" @@ -17329,6 +22418,17 @@ __metadata: languageName: node linkType: hard +"postcss-normalize-url@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-normalize-url@npm:6.0.2" + dependencies: + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.4.31 + checksum: bef51a18bbfee4fbf0381fec3c91e6c0dace36fca053bbd5f228e653d2732b6df3985525d79c4f7fc89f840ed07eb6d226e9d7503ecdc6f16d6d80cacae9df33 + languageName: node + linkType: hard + "postcss-normalize-whitespace@npm:^5.1.1": version: 5.1.1 resolution: "postcss-normalize-whitespace@npm:5.1.1" @@ -17340,6 +22440,17 @@ __metadata: languageName: node linkType: hard +"postcss-normalize-whitespace@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-normalize-whitespace@npm:6.0.2" + dependencies: + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.4.31 + checksum: 6081eb3a4b305749eec02c00a95c2d236336a77ee636bb1d939f18d5dfa5ba82b7cf7fa072e83f9133d0bc984276596af3fe468bdd67c742ce69e9c63dbc218d + languageName: node + linkType: hard + "postcss-normalize@npm:^10.0.1": version: 10.0.1 resolution: "postcss-normalize@npm:10.0.1" @@ -17363,6 +22474,15 @@ __metadata: languageName: node linkType: hard +"postcss-opacity-percentage@npm:^3.0.0": + version: 3.0.0 + resolution: "postcss-opacity-percentage@npm:3.0.0" + peerDependencies: + postcss: ^8.4 + checksum: dc813113f05f91f1c87ab3c125911f9e5989d1f3fc7cc5586a165901a63c0d02077d134df844391ea5624088680c6b3cee75bc33b8efdcaf340a91046e47e4e1 + languageName: node + linkType: hard + "postcss-ordered-values@npm:^5.1.3": version: 5.1.3 resolution: "postcss-ordered-values@npm:5.1.3" @@ -17375,6 +22495,18 @@ __metadata: languageName: node linkType: hard +"postcss-ordered-values@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-ordered-values@npm:6.0.2" + dependencies: + cssnano-utils: ^4.0.2 + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.4.31 + checksum: c3d96177b4ffa43754e835e30c40043cc75ab1e95eb6c55ac8723eb48c13a12e986250e63d96619bbbd1a098876a1c0c1b3b7a8e1de1108a009cf7aa0beac834 + languageName: node + linkType: hard + "postcss-overflow-shorthand@npm:^3.0.4": version: 3.0.4 resolution: "postcss-overflow-shorthand@npm:3.0.4" @@ -17386,6 +22518,17 @@ __metadata: languageName: node linkType: hard +"postcss-overflow-shorthand@npm:^6.0.0": + version: 6.0.0 + resolution: "postcss-overflow-shorthand@npm:6.0.0" + dependencies: + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.4 + checksum: 80f07e0beb97b7ac5dac590802591fc93392b0d7a9678e17998b4d34ee0cca637665232c7ea88b3a4342192bc9a2a4f5c757ad86b837a5fd59d083d37cc7da16 + languageName: node + linkType: hard + "postcss-page-break@npm:^3.0.4": version: 3.0.4 resolution: "postcss-page-break@npm:3.0.4" @@ -17395,6 +22538,17 @@ __metadata: languageName: node linkType: hard +"postcss-place@npm:^10.0.0": + version: 10.0.0 + resolution: "postcss-place@npm:10.0.0" + dependencies: + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.4 + checksum: 738cd0dc2412cf573bcfb2f7dce8e1cd21887f61c8808f55114f08fb8fbf03715e957fdd8859241eecebe400a5202771f513610b04e0f17c7742f6a5ea3bafb3 + languageName: node + linkType: hard + "postcss-place@npm:^7.0.5": version: 7.0.5 resolution: "postcss-place@npm:7.0.5" @@ -17406,6 +22560,87 @@ __metadata: languageName: node linkType: hard +"postcss-preset-env@npm:^10.2.1": + version: 10.6.1 + resolution: "postcss-preset-env@npm:10.6.1" + dependencies: + "@csstools/postcss-alpha-function": ^1.0.1 + "@csstools/postcss-cascade-layers": ^5.0.2 + "@csstools/postcss-color-function": ^4.0.12 + "@csstools/postcss-color-function-display-p3-linear": ^1.0.1 + "@csstools/postcss-color-mix-function": ^3.0.12 + "@csstools/postcss-color-mix-variadic-function-arguments": ^1.0.2 + "@csstools/postcss-content-alt-text": ^2.0.8 + "@csstools/postcss-contrast-color-function": ^2.0.12 + "@csstools/postcss-exponential-functions": ^2.0.9 + "@csstools/postcss-font-format-keywords": ^4.0.0 + "@csstools/postcss-gamut-mapping": ^2.0.11 + "@csstools/postcss-gradients-interpolation-method": ^5.0.12 + "@csstools/postcss-hwb-function": ^4.0.12 + "@csstools/postcss-ic-unit": ^4.0.4 + "@csstools/postcss-initial": ^2.0.1 + "@csstools/postcss-is-pseudo-class": ^5.0.3 + "@csstools/postcss-light-dark-function": ^2.0.11 + "@csstools/postcss-logical-float-and-clear": ^3.0.0 + "@csstools/postcss-logical-overflow": ^2.0.0 + "@csstools/postcss-logical-overscroll-behavior": ^2.0.0 + "@csstools/postcss-logical-resize": ^3.0.0 + "@csstools/postcss-logical-viewport-units": ^3.0.4 + "@csstools/postcss-media-minmax": ^2.0.9 + "@csstools/postcss-media-queries-aspect-ratio-number-values": ^3.0.5 + "@csstools/postcss-nested-calc": ^4.0.0 + "@csstools/postcss-normalize-display-values": ^4.0.1 + "@csstools/postcss-oklab-function": ^4.0.12 + "@csstools/postcss-position-area-property": ^1.0.0 + "@csstools/postcss-progressive-custom-properties": ^4.2.1 + "@csstools/postcss-property-rule-prelude-list": ^1.0.0 + "@csstools/postcss-random-function": ^2.0.1 + "@csstools/postcss-relative-color-syntax": ^3.0.12 + "@csstools/postcss-scope-pseudo-class": ^4.0.1 + "@csstools/postcss-sign-functions": ^1.1.4 + "@csstools/postcss-stepped-value-functions": ^4.0.9 + "@csstools/postcss-syntax-descriptor-syntax-production": ^1.0.1 + "@csstools/postcss-system-ui-font-family": ^1.0.0 + "@csstools/postcss-text-decoration-shorthand": ^4.0.3 + "@csstools/postcss-trigonometric-functions": ^4.0.9 + "@csstools/postcss-unset-value": ^4.0.0 + autoprefixer: ^10.4.23 + browserslist: ^4.28.1 + css-blank-pseudo: ^7.0.1 + css-has-pseudo: ^7.0.3 + css-prefers-color-scheme: ^10.0.0 + cssdb: ^8.6.0 + postcss-attribute-case-insensitive: ^7.0.1 + postcss-clamp: ^4.1.0 + postcss-color-functional-notation: ^7.0.12 + postcss-color-hex-alpha: ^10.0.0 + postcss-color-rebeccapurple: ^10.0.0 + postcss-custom-media: ^11.0.6 + postcss-custom-properties: ^14.0.6 + postcss-custom-selectors: ^8.0.5 + postcss-dir-pseudo-class: ^9.0.1 + postcss-double-position-gradients: ^6.0.4 + postcss-focus-visible: ^10.0.1 + postcss-focus-within: ^9.0.1 + postcss-font-variant: ^5.0.0 + postcss-gap-properties: ^6.0.0 + postcss-image-set-function: ^7.0.0 + postcss-lab-function: ^7.0.12 + postcss-logical: ^8.1.0 + postcss-nesting: ^13.0.2 + postcss-opacity-percentage: ^3.0.0 + postcss-overflow-shorthand: ^6.0.0 + postcss-page-break: ^3.0.4 + postcss-place: ^10.0.0 + postcss-pseudo-class-any-link: ^10.0.1 + postcss-replace-overflow-wrap: ^4.0.0 + postcss-selector-not: ^8.0.1 + peerDependencies: + postcss: ^8.4 + checksum: 6a7d4f6680e8723f241aca9219c90b507d7401f8778db889e4bfc850f415e9f655277c74ffae276ce9695e9d43710a6d84dd96055b1b76eed75cb833440f0cd2 + languageName: node + linkType: hard + "postcss-preset-env@npm:^7.0.1": version: 7.8.3 resolution: "postcss-preset-env@npm:7.8.3" @@ -17465,6 +22700,17 @@ __metadata: languageName: node linkType: hard +"postcss-pseudo-class-any-link@npm:^10.0.1": + version: 10.0.1 + resolution: "postcss-pseudo-class-any-link@npm:10.0.1" + dependencies: + postcss-selector-parser: ^7.0.0 + peerDependencies: + postcss: ^8.4 + checksum: 376525d1a6fa223d908deb884b93d5cb76f4fa7431c090a8ada63e5ee9657bec7bf8e23eff1c36264c051c5a653928e38392165a862b7c5bf5e39e9364383fce + languageName: node + linkType: hard + "postcss-pseudo-class-any-link@npm:^7.1.6": version: 7.1.6 resolution: "postcss-pseudo-class-any-link@npm:7.1.6" @@ -17476,6 +22722,17 @@ __metadata: languageName: node linkType: hard +"postcss-reduce-idents@npm:^6.0.3": + version: 6.0.3 + resolution: "postcss-reduce-idents@npm:6.0.3" + dependencies: + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.4.31 + checksum: 1feff316838f947386c908f50807cf1b9589fd09b8e8df633a01f2640af5492833cc892448938ceba10ab96826c44767b8f2e1569d587579423f2db81202f7c7 + languageName: node + linkType: hard + "postcss-reduce-initial@npm:^5.1.2": version: 5.1.2 resolution: "postcss-reduce-initial@npm:5.1.2" @@ -17488,6 +22745,18 @@ __metadata: languageName: node linkType: hard +"postcss-reduce-initial@npm:^6.1.0": + version: 6.1.0 + resolution: "postcss-reduce-initial@npm:6.1.0" + dependencies: + browserslist: ^4.23.0 + caniuse-api: ^3.0.0 + peerDependencies: + postcss: ^8.4.31 + checksum: 39e4034ffbf62a041b66944c5cebc4b17f656e76b97568f7f6230b0b886479e5c75b02ae4ba48c472cb0bde47489f9ed1fe6110ae8cff0d7b7165f53c2d64a12 + languageName: node + linkType: hard + "postcss-reduce-transforms@npm:^5.1.0": version: 5.1.0 resolution: "postcss-reduce-transforms@npm:5.1.0" @@ -17499,6 +22768,17 @@ __metadata: languageName: node linkType: hard +"postcss-reduce-transforms@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-reduce-transforms@npm:6.0.2" + dependencies: + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.4.31 + checksum: c424cc554eb5d253b7687b64925a13fc16759f058795d223854f5a20d9bca641b5f25d0559d03287e63f07a4629c24ac78156adcf604483fcad3c51721da0a08 + languageName: node + linkType: hard + "postcss-replace-overflow-wrap@npm:^4.0.0": version: 4.0.0 resolution: "postcss-replace-overflow-wrap@npm:4.0.0" @@ -17519,7 +22799,18 @@ __metadata: languageName: node linkType: hard -"postcss-selector-parser@npm:^6.0.10, postcss-selector-parser@npm:^6.0.4, postcss-selector-parser@npm:^6.0.5, postcss-selector-parser@npm:^6.0.9, postcss-selector-parser@npm:^6.1.1, postcss-selector-parser@npm:^6.1.2": +"postcss-selector-not@npm:^8.0.1": + version: 8.0.1 + resolution: "postcss-selector-not@npm:8.0.1" + dependencies: + postcss-selector-parser: ^7.0.0 + peerDependencies: + postcss: ^8.4 + checksum: 28c1f7863ac85016ecd695304ee1eb21b1128eacba333d6d4540fd93691c58ff6329ac323b6a640f2da918e95c7b58e8f534c8b6e2ed016f6e31cdfdc743edbc + languageName: node + linkType: hard + +"postcss-selector-parser@npm:^6.0.10, postcss-selector-parser@npm:^6.0.11, postcss-selector-parser@npm:^6.0.16, postcss-selector-parser@npm:^6.0.4, postcss-selector-parser@npm:^6.0.5, postcss-selector-parser@npm:^6.0.9, postcss-selector-parser@npm:^6.1.1, postcss-selector-parser@npm:^6.1.2": version: 6.1.2 resolution: "postcss-selector-parser@npm:6.1.2" dependencies: @@ -17539,6 +22830,17 @@ __metadata: languageName: node linkType: hard +"postcss-sort-media-queries@npm:^5.2.0": + version: 5.2.0 + resolution: "postcss-sort-media-queries@npm:5.2.0" + dependencies: + sort-css-media-queries: 2.2.0 + peerDependencies: + postcss: ^8.4.23 + checksum: d4a976a64b53234762cc35c06ce97c1684bd7a64ead17e84c2047676c7307945be7c005235e6aac7c4620e1f835d6ba1a7dcf018ab7fe0a47657c62c96ad9f35 + languageName: node + linkType: hard + "postcss-svgo@npm:^5.1.0": version: 5.1.0 resolution: "postcss-svgo@npm:5.1.0" @@ -17551,14 +22853,37 @@ __metadata: languageName: node linkType: hard +"postcss-svgo@npm:^6.0.3": + version: 6.0.3 + resolution: "postcss-svgo@npm:6.0.3" + dependencies: + postcss-value-parser: ^4.2.0 + svgo: ^3.2.0 + peerDependencies: + postcss: ^8.4.31 + checksum: 1a7d1c8dea555884a7791e28ec2c22ea92331731067584ff5a23042a0e615f88fefde04e1140f11c262a728ef9fab6851423b40b9c47f9ae05353bd3c0ff051a + languageName: node + linkType: hard + "postcss-unique-selectors@npm:^5.1.1": version: 5.1.1 resolution: "postcss-unique-selectors@npm:5.1.1" dependencies: - postcss-selector-parser: ^6.0.5 + postcss-selector-parser: ^6.0.5 + peerDependencies: + postcss: ^8.2.15 + checksum: 637e7b786e8558265775c30400c54b6b3b24d4748923f4a39f16a65fd0e394f564ccc9f0a1d3c0e770618a7637a7502ea1d0d79f731d429cb202255253c23278 + languageName: node + linkType: hard + +"postcss-unique-selectors@npm:^6.0.4": + version: 6.0.4 + resolution: "postcss-unique-selectors@npm:6.0.4" + dependencies: + postcss-selector-parser: ^6.0.16 peerDependencies: - postcss: ^8.2.15 - checksum: 637e7b786e8558265775c30400c54b6b3b24d4748923f4a39f16a65fd0e394f564ccc9f0a1d3c0e770618a7637a7502ea1d0d79f731d429cb202255253c23278 + postcss: ^8.4.31 + checksum: b09df9943b4e858e88b30f3d279ce867a0490df806f1f947d286b0a4e95ba923f1229c385e5bf365f4f124f1edccda41ec18ccad4ba8798d829279d6dc971203 languageName: node linkType: hard @@ -17569,6 +22894,15 @@ __metadata: languageName: node linkType: hard +"postcss-zindex@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-zindex@npm:6.0.2" + peerDependencies: + postcss: ^8.4.31 + checksum: 394119e47b0fb098dc53d1bcf71b5500ab29605fe106526b2e81290bff179174ee00a82a4d4be5a42d4ef4138e8a3d6aabeef3b06cf7cb15b851848c8585d53b + languageName: node + linkType: hard + "postcss@npm:^7.0.35": version: 7.0.39 resolution: "postcss@npm:7.0.39" @@ -17579,7 +22913,7 @@ __metadata: languageName: node linkType: hard -"postcss@npm:^8.3.5, postcss@npm:^8.4.27, postcss@npm:^8.4.33, postcss@npm:^8.4.4, postcss@npm:^8.4.43, postcss@npm:^8.4.47, postcss@npm:^8.4.49, postcss@npm:^8.5.6": +"postcss@npm:^8.3.5, postcss@npm:^8.4.21, postcss@npm:^8.4.24, postcss@npm:^8.4.27, postcss@npm:^8.4.33, postcss@npm:^8.4.4, postcss@npm:^8.4.43, postcss@npm:^8.4.47, postcss@npm:^8.4.49, postcss@npm:^8.5.4, postcss@npm:^8.5.6": version: 8.5.6 resolution: "postcss@npm:8.5.6" dependencies: @@ -17695,6 +23029,25 @@ __metadata: languageName: node linkType: hard +"pretty-time@npm:^1.1.0": + version: 1.1.0 + resolution: "pretty-time@npm:1.1.0" + checksum: a319e7009aadbc6cfedbd8b66861327d3a0c68bd3e8794bf5b86f62b40b01b9479c5a70c76bb368ad454acce52a1216daee460cc825766e2442c04f3a84a02c9 + languageName: node + linkType: hard + +"prism-react-renderer@npm:^2.3.0": + version: 2.4.1 + resolution: "prism-react-renderer@npm:2.4.1" + dependencies: + "@types/prismjs": ^1.26.0 + clsx: ^2.0.0 + peerDependencies: + react: ">=16.0.0" + checksum: ddd5490a1335629addde9535db7872f0aee8dbce048818dd6e4c3972c779780af13d669c12d3f2fbb54c5b22d1578e50945099ef1a24dd445f33774e87d85e6e + languageName: node + linkType: hard + "prisma@npm:^6.2.1": version: 6.19.2 resolution: "prisma@npm:6.19.2" @@ -17712,6 +23065,13 @@ __metadata: languageName: node linkType: hard +"prismjs@npm:^1.29.0": + version: 1.30.0 + resolution: "prismjs@npm:1.30.0" + checksum: a68eddd4c5f1c506badb5434b0b28a7cc2479ed1df91bc4218e6833c7971ef40c50ec481ea49749ac964256acb78d8b66a6bd11554938e8998e46c18b5f9a580 + languageName: node + linkType: hard + "proc-log@npm:^6.0.0": version: 6.1.0 resolution: "proc-log@npm:6.1.0" @@ -17787,6 +23147,13 @@ __metadata: languageName: node linkType: hard +"proto-list@npm:~1.2.1": + version: 1.2.4 + resolution: "proto-list@npm:1.2.4" + checksum: 4d4826e1713cbfa0f15124ab0ae494c91b597a3c458670c9714c36e8baddf5a6aad22842776f2f5b137f259c8533e741771445eb8df82e861eea37a6eaba03f7 + languageName: node + linkType: hard + "proxy-addr@npm:^2.0.7, proxy-addr@npm:~2.0.7": version: 2.0.7 resolution: "proxy-addr@npm:2.0.7" @@ -17837,6 +23204,15 @@ __metadata: languageName: node linkType: hard +"pupa@npm:^3.1.0": + version: 3.3.0 + resolution: "pupa@npm:3.3.0" + dependencies: + escape-goat: ^4.0.0 + checksum: a26b57cb4ff761495628b3630ab65fd97229d19314dbd9a08133d34f3f85fdb368da478f7b4a57647660c6d2973f0dae740668f8809c5861e3ede99e938ded05 + languageName: node + linkType: hard + "pure-rand@npm:^6.1.0": version: 6.1.0 resolution: "pure-rand@npm:6.1.0" @@ -17844,6 +23220,22 @@ __metadata: languageName: node linkType: hard +"pvtsutils@npm:^1.3.6": + version: 1.3.6 + resolution: "pvtsutils@npm:1.3.6" + dependencies: + tslib: ^2.8.1 + checksum: 97b023b46d7b95bff004f8340efc465c1d995f35d7e97a2ef2e28d5e160f5ca47b48f42463b6be92b4341452a6b8c555feb2b1eb59ee90b97bd5d6fc86ffb186 + languageName: node + linkType: hard + +"pvutils@npm:^1.1.3": + version: 1.1.5 + resolution: "pvutils@npm:1.1.5" + checksum: b86a8d1e74aa430faea75b510e33e5d5315213616e3c2870c2a3c0c152fd5eab08a52d3fdda3a4c711990d5e8e43918b5bc364fba531f81192146c5cbb9b7aa6 + languageName: node + linkType: hard + "q@npm:^1.1.2": version: 1.5.1 resolution: "q@npm:1.5.1" @@ -17874,6 +23266,13 @@ __metadata: languageName: node linkType: hard +"quick-lru@npm:^5.1.1": + version: 5.1.1 + resolution: "quick-lru@npm:5.1.1" + checksum: a516faa25574be7947969883e6068dbe4aa19e8ef8e8e0fd96cddd6d36485e9106d85c0041a27153286b0770b381328f4072aa40d3b18a19f5f7d2b78b94b5ed + languageName: node + linkType: hard + "raf-schd@npm:^4.0.3": version: 4.0.3 resolution: "raf-schd@npm:4.0.3" @@ -17899,6 +23298,13 @@ __metadata: languageName: node linkType: hard +"range-parser@npm:1.2.0": + version: 1.2.0 + resolution: "range-parser@npm:1.2.0" + checksum: bdf397f43fedc15c559d3be69c01dedf38444ca7a1610f5bf5955e3f3da6057a892f34691e7ebdd8c7e1698ce18ef6c4d4811f70e658dda3ff230ef741f8423a + languageName: node + linkType: hard + "range-parser@npm:^1.2.1, range-parser@npm:~1.2.1": version: 1.2.1 resolution: "range-parser@npm:1.2.1" @@ -17940,7 +23346,7 @@ __metadata: languageName: node linkType: hard -"rc@npm:^1.2.7": +"rc@npm:1.2.8, rc@npm:^1.2.7": version: 1.2.8 resolution: "rc@npm:1.2.8" dependencies: @@ -18035,6 +23441,18 @@ __metadata: languageName: node linkType: hard +"react-dom@npm:^18.0.0": + version: 18.3.1 + resolution: "react-dom@npm:18.3.1" + dependencies: + loose-envify: ^1.1.0 + scheduler: ^0.23.2 + peerDependencies: + react: ^18.3.1 + checksum: 298954ecd8f78288dcaece05e88b570014d8f6dce5db6f66e6ee91448debeb59dcd31561dddb354eee47e6c1bb234669459060deb238ed0213497146e555a0b9 + languageName: node + linkType: hard + "react-draggable@npm:^4.4.6": version: 4.5.0 resolution: "react-draggable@npm:4.5.0" @@ -18073,7 +23491,7 @@ __metadata: languageName: node linkType: hard -"react-fast-compare@npm:^3.1.1": +"react-fast-compare@npm:^3.1.1, react-fast-compare@npm:^3.2.0": version: 3.2.2 resolution: "react-fast-compare@npm:3.2.2" checksum: 2071415b4f76a3e6b55c84611c4d24dcb12ffc85811a2840b5a3f1ff2d1a99be1020d9437ee7c6e024c9f4cbb84ceb35e48cf84f28fcb00265ad2dfdd3947704 @@ -18090,6 +23508,22 @@ __metadata: languageName: node linkType: hard +"react-helmet-async@npm:@slorber/react-helmet-async@1.3.0": + version: 1.3.0 + resolution: "@slorber/react-helmet-async@npm:1.3.0" + dependencies: + "@babel/runtime": ^7.12.5 + invariant: ^2.2.4 + prop-types: ^15.7.2 + react-fast-compare: ^3.2.0 + shallowequal: ^1.1.0 + peerDependencies: + react: ^16.6.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.6.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + checksum: 2bd080035aa4145761cc08caa2a64f1d8e867ddda71967936b1325f84c5bc7161ac77c1095818952bc5bb09c78ffbd594e7d0508d54255c5bfbc15e3769ef538 + languageName: node + linkType: hard + "react-helmet@npm:^6.1.0": version: 6.1.0 resolution: "react-helmet@npm:6.1.0" @@ -18151,6 +23585,38 @@ __metadata: languageName: node linkType: hard +"react-json-view-lite@npm:^2.3.0": + version: 2.5.0 + resolution: "react-json-view-lite@npm:2.5.0" + peerDependencies: + react: ^18.0.0 || ^19.0.0 + checksum: 9009cf9c8b5752ade7ee72f234be6ed17c24b6422742f5512bfa1c8a95d24cb128d4df1d994d28d0b1e0e7f06b0ebf84713171e6841602d46b30c3604fbda2b7 + languageName: node + linkType: hard + +"react-loadable-ssr-addon-v5-slorber@npm:^1.0.1": + version: 1.0.1 + resolution: "react-loadable-ssr-addon-v5-slorber@npm:1.0.1" + dependencies: + "@babel/runtime": ^7.10.3 + peerDependencies: + react-loadable: "*" + webpack: ">=4.41.1 || 5.x" + checksum: 1cf7ceb488d329a5be15f891dae16727fb7ade08ef57826addd21e2c3d485e2440259ef8be94f4d54e9afb4bcbd2fcc22c3c5bad92160c9c06ae6ba7b5562497 + languageName: node + linkType: hard + +"react-loadable@npm:@docusaurus/react-loadable@6.0.0": + version: 6.0.0 + resolution: "@docusaurus/react-loadable@npm:6.0.0" + dependencies: + "@types/react": "*" + peerDependencies: + react: "*" + checksum: 4c32061b2fc10689d5d8ba11ead71b69e4c8a55fcfeafb551a6747b1a7b496c4f2d8dbb5d023f5cafc2a9aea9d14582bdb324d11e6f9b8c3049d45b74439203f + languageName: node + linkType: hard + "react-markdown@npm:^9.0.3": version: 9.1.0 resolution: "react-markdown@npm:9.1.0" @@ -18265,7 +23731,19 @@ __metadata: languageName: node linkType: hard -"react-router-dom@npm:^5.2.0": +"react-router-config@npm:^5.1.1": + version: 5.1.1 + resolution: "react-router-config@npm:5.1.1" + dependencies: + "@babel/runtime": ^7.1.2 + peerDependencies: + react: ">=15" + react-router: ">=5" + checksum: bde7ee79444454bf7c3737fd9c5c268021012c8cc37bc19116b2e7daa28c4231598c275816c7f32c16f9f974dc707b91de279291a5e39efce2e1b1569355b87a + languageName: node + linkType: hard + +"react-router-dom@npm:^5.2.0, react-router-dom@npm:^5.3.4": version: 5.3.4 resolution: "react-router-dom@npm:5.3.4" dependencies: @@ -18282,7 +23760,7 @@ __metadata: languageName: node linkType: hard -"react-router@npm:5.3.4": +"react-router@npm:5.3.4, react-router@npm:^5.3.4": version: 5.3.4 resolution: "react-router@npm:5.3.4" dependencies: @@ -18426,6 +23904,15 @@ __metadata: languageName: node linkType: hard +"react@npm:^18.0.0": + version: 18.3.1 + resolution: "react@npm:18.3.1" + dependencies: + loose-envify: ^1.1.0 + checksum: a27bcfa8ff7c15a1e50244ad0d0c1cb2ad4375eeffefd266a64889beea6f6b64c4966c9b37d14ee32d6c9fcd5aa6ba183b6988167ab4d127d13e7cb5b386a376 + languageName: node + linkType: hard + "read-cache@npm:^1.0.0": version: 1.0.0 resolution: "read-cache@npm:1.0.0" @@ -18505,6 +23992,56 @@ __metadata: languageName: node linkType: hard +"recma-build-jsx@npm:^1.0.0": + version: 1.0.0 + resolution: "recma-build-jsx@npm:1.0.0" + dependencies: + "@types/estree": ^1.0.0 + estree-util-build-jsx: ^3.0.0 + vfile: ^6.0.0 + checksum: ba82fe08efdf5ecd178ab76a08a4acac792a41d9f38aea99f93cb3d9e577ba8952620c547e730ba6717c13efa08fdb3dfe893bccfa9717f5a81d3fb2ab20c572 + languageName: node + linkType: hard + +"recma-jsx@npm:^1.0.0": + version: 1.0.1 + resolution: "recma-jsx@npm:1.0.1" + dependencies: + acorn-jsx: ^5.0.0 + estree-util-to-js: ^2.0.0 + recma-parse: ^1.0.0 + recma-stringify: ^1.0.0 + unified: ^11.0.0 + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + checksum: 4227ec707d2711f8c0f765792e7508f9bd0897991b2479e4612250b4fbba67fc2b06fe65ae8dfeba52a41b910f4e84c18e860b95424526273e8a9fd6e3483f43 + languageName: node + linkType: hard + +"recma-parse@npm:^1.0.0": + version: 1.0.0 + resolution: "recma-parse@npm:1.0.0" + dependencies: + "@types/estree": ^1.0.0 + esast-util-from-js: ^2.0.0 + unified: ^11.0.0 + vfile: ^6.0.0 + checksum: 676b2097a63ba444985a61af51c2628a546a2537a9ca036ed2249a627fb096f3373139765388b60164e6f5a50c819146a3660351e3f993a360ef107f2ab1c6f8 + languageName: node + linkType: hard + +"recma-stringify@npm:^1.0.0": + version: 1.0.0 + resolution: "recma-stringify@npm:1.0.0" + dependencies: + "@types/estree": ^1.0.0 + estree-util-to-js: ^2.0.0 + unified: ^11.0.0 + vfile: ^6.0.0 + checksum: 3a4f80fe0f6bc11fefa71782dfedb43c28b42518dea450cd1b1591057d9d570f83c85d645bf5ed6da2e47de15a021172c076a8ff4675799855d9f9436cec3c82 + languageName: node + linkType: hard + "recursive-readdir@npm:^2.2.2": version: 2.2.3 resolution: "recursive-readdir@npm:2.2.3" @@ -18531,6 +24068,13 @@ __metadata: languageName: node linkType: hard +"reflect-metadata@npm:^0.2.2": + version: 0.2.2 + resolution: "reflect-metadata@npm:0.2.2" + checksum: a66c7b583e4efdd8f3c3124fbff33da2d0c86d8280617516308b32b2159af7a3698c961db3246387f56f6316b1d33a608f39bb2b49d813316dfc58f6d3bf3210 + languageName: node + linkType: hard + "reflect.getprototypeof@npm:^1.0.6, reflect.getprototypeof@npm:^1.0.9": version: 1.0.10 resolution: "reflect.getprototypeof@npm:1.0.10" @@ -18612,6 +24156,24 @@ __metadata: languageName: node linkType: hard +"registry-auth-token@npm:^5.0.1": + version: 5.1.1 + resolution: "registry-auth-token@npm:5.1.1" + dependencies: + "@pnpm/npm-conf": ^3.0.2 + checksum: 36cf27fca6419e4d92c27419c5a333aea1d9dec62f7fb812fa8d8d95dcfa4124e57f22bb944512f5f97ae0e0cda90c28b3a5f0e7ace0b5620d84a8b6b2cab862 + languageName: node + linkType: hard + +"registry-url@npm:^6.0.0": + version: 6.0.1 + resolution: "registry-url@npm:6.0.1" + dependencies: + rc: 1.2.8 + checksum: 33712aa1b489aab7aba2191c1cdadfdd71f5bf166d4792d81744a6be332c160bd7d9273af8269d8a01284b9562f14a5b31b7abcf7ad9306c44887ecff51c89ab + languageName: node + linkType: hard + "regjsgen@npm:^0.8.0": version: 0.8.0 resolution: "regjsgen@npm:0.8.0" @@ -18630,6 +24192,28 @@ __metadata: languageName: node linkType: hard +"rehype-raw@npm:^7.0.0": + version: 7.0.0 + resolution: "rehype-raw@npm:7.0.0" + dependencies: + "@types/hast": ^3.0.0 + hast-util-raw: ^9.0.0 + vfile: ^6.0.0 + checksum: f9e28dcbf4c6c7d91a97c10a840310f18ef3268aa45abb3e0428b6b191ff3c4fa8f753b910d768588a2dac5c7da7e557b4ddc3f1b6cd252e8d20cb62d60c65ed + languageName: node + linkType: hard + +"rehype-recma@npm:^1.0.0": + version: 1.0.0 + resolution: "rehype-recma@npm:1.0.0" + dependencies: + "@types/estree": ^1.0.0 + "@types/hast": ^3.0.0 + hast-util-to-estree: ^3.0.0 + checksum: d3d544ad4a18485ec6b03a194b40473f96e2169c63d6a8ee3ce9af5e87b946c308fb9549b53e010c7dd39740337e387bb1a8856ce1b47f3e957b696f1d5b2d0c + languageName: node + linkType: hard + "relateurl@npm:^0.2.7": version: 0.2.7 resolution: "relateurl@npm:0.2.7" @@ -18637,6 +24221,67 @@ __metadata: languageName: node linkType: hard +"remark-directive@npm:^3.0.0": + version: 3.0.1 + resolution: "remark-directive@npm:3.0.1" + dependencies: + "@types/mdast": ^4.0.0 + mdast-util-directive: ^3.0.0 + micromark-extension-directive: ^3.0.0 + unified: ^11.0.0 + checksum: e7f273199fbb1c6946863ca3f8293791ee8fa997e373cd20da67d02fdb6a534c728212a93eaf3c9354b6c4416a56ae83098b35554e1e4ed7dca770c9baf69455 + languageName: node + linkType: hard + +"remark-emoji@npm:^4.0.0": + version: 4.0.1 + resolution: "remark-emoji@npm:4.0.1" + dependencies: + "@types/mdast": ^4.0.2 + emoticon: ^4.0.1 + mdast-util-find-and-replace: ^3.0.1 + node-emoji: ^2.1.0 + unified: ^11.0.4 + checksum: 2c02d8c0b694535a9f0c4fe39180cb89a8fbd07eb873c94842c34dfde566b8a6703df9d28fe175a8c28584f96252121de722862baa756f2d875f2f1a4352c1f4 + languageName: node + linkType: hard + +"remark-frontmatter@npm:^5.0.0": + version: 5.0.0 + resolution: "remark-frontmatter@npm:5.0.0" + dependencies: + "@types/mdast": ^4.0.0 + mdast-util-frontmatter: ^2.0.0 + micromark-extension-frontmatter: ^2.0.0 + unified: ^11.0.0 + checksum: b36e11d528d1d0172489c74ce7961bb6073f7272e71ea1349f765fc79c4246a758aef949174d371a088c48e458af776fcfbb3b043c49cd1120ca8239aeafe16a + languageName: node + linkType: hard + +"remark-gfm@npm:^4.0.0": + version: 4.0.1 + resolution: "remark-gfm@npm:4.0.1" + dependencies: + "@types/mdast": ^4.0.0 + mdast-util-gfm: ^3.0.0 + micromark-extension-gfm: ^3.0.0 + remark-parse: ^11.0.0 + remark-stringify: ^11.0.0 + unified: ^11.0.0 + checksum: b278f51c4496f15ad868b72bf2eb2066c23a0892b5885544d3a4c233c964d44e51a0efe22d3fb33db4fbac92aefd51bb33453b8e73077b041a12b8269a02c17d + languageName: node + linkType: hard + +"remark-mdx@npm:^3.0.0": + version: 3.1.1 + resolution: "remark-mdx@npm:3.1.1" + dependencies: + mdast-util-mdx: ^3.0.0 + micromark-extension-mdxjs: ^3.0.0 + checksum: 9e6406ba83e545b5232ce98de71c29ad5746c2d920eed070a2c58687412453875bad52dfdfaf21bee6de59d3a45fa84cf785b3111c5eb4822f29b67cf1dfec96 + languageName: node + linkType: hard + "remark-parse@npm:^11.0.0": version: 11.0.0 resolution: "remark-parse@npm:11.0.0" @@ -18662,6 +24307,17 @@ __metadata: languageName: node linkType: hard +"remark-stringify@npm:^11.0.0": + version: 11.0.0 + resolution: "remark-stringify@npm:11.0.0" + dependencies: + "@types/mdast": ^4.0.0 + mdast-util-to-markdown: ^2.0.0 + unified: ^11.0.0 + checksum: 59e07460eb629d6c3b3c0f438b0b236e7e6858fd5ab770303078f5a556ec00354d9c7fb9ef6d5f745a4617ac7da1ab618b170fbb4dac120e183fecd9cc86bce6 + languageName: node + linkType: hard + "remove-accents@npm:0.5.0": version: 0.5.0 resolution: "remove-accents@npm:0.5.0" @@ -18682,6 +24338,13 @@ __metadata: languageName: node linkType: hard +"repeat-string@npm:^1.0.0": + version: 1.6.1 + resolution: "repeat-string@npm:1.6.1" + checksum: 1b809fc6db97decdc68f5b12c4d1a671c8e3f65ec4a40c238bc5200e44e85bcc52a54f78268ab9c29fcf5fe4f1343e805420056d1f30fa9a9ee4c2d93e3cc6c0 + languageName: node + linkType: hard + "require-directory@npm:^2.1.1": version: 2.1.1 resolution: "require-directory@npm:2.1.1" @@ -18696,6 +24359,13 @@ __metadata: languageName: node linkType: hard +"require-like@npm:>= 0.1.1": + version: 0.1.2 + resolution: "require-like@npm:0.1.2" + checksum: edb8331f05fd807381a75b76f6cca9f0ce8acaa2e910b7e116541799aa970bfbc64fde5fd6adb3a6917dba346f8386ebbddb81614c24e8dad1b4290c7af9535e + languageName: node + linkType: hard + "require-main-filename@npm:^2.0.0": version: 2.0.0 resolution: "require-main-filename@npm:2.0.0" @@ -18731,6 +24401,13 @@ __metadata: languageName: node linkType: hard +"resolve-alpn@npm:^1.2.0": + version: 1.2.1 + resolution: "resolve-alpn@npm:1.2.1" + checksum: f558071fcb2c60b04054c99aebd572a2af97ef64128d59bef7ab73bd50d896a222a056de40ffc545b633d99b304c259ea9d0c06830d5c867c34f0bfa60b8eae0 + languageName: node + linkType: hard + "resolve-cwd@npm:^3.0.0": version: 3.0.0 resolution: "resolve-cwd@npm:3.0.0" @@ -18796,7 +24473,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.1.7, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.10, resolve@npm:^1.22.4, resolve@npm:^1.22.8": +"resolve@npm:^1.1.7, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.10, resolve@npm:^1.22.11, resolve@npm:^1.22.4, resolve@npm:^1.22.8": version: 1.22.11 resolution: "resolve@npm:1.22.11" dependencies: @@ -18822,7 +24499,7 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@^1.1.7#~builtin, resolve@patch:resolve@^1.19.0#~builtin, resolve@patch:resolve@^1.20.0#~builtin, resolve@patch:resolve@^1.22.10#~builtin, resolve@patch:resolve@^1.22.4#~builtin, resolve@patch:resolve@^1.22.8#~builtin": +"resolve@patch:resolve@^1.1.7#~builtin, resolve@patch:resolve@^1.19.0#~builtin, resolve@patch:resolve@^1.20.0#~builtin, resolve@patch:resolve@^1.22.10#~builtin, resolve@patch:resolve@^1.22.11#~builtin, resolve@patch:resolve@^1.22.4#~builtin, resolve@patch:resolve@^1.22.8#~builtin": version: 1.22.11 resolution: "resolve@patch:resolve@npm%3A1.22.11#~builtin::version=1.22.11&hash=07638b" dependencies: @@ -18848,6 +24525,15 @@ __metadata: languageName: node linkType: hard +"responselike@npm:^3.0.0": + version: 3.0.0 + resolution: "responselike@npm:3.0.0" + dependencies: + lowercase-keys: ^3.0.0 + checksum: e0cc9be30df4f415d6d83cdede3c5c887cd4a73e7cc1708bcaab1d50a28d15acb68460ac5b02bcc55a42f3d493729c8856427dcf6e57e6e128ad05cba4cfb95e + languageName: node + linkType: hard + "retry@npm:^0.12.0": version: 0.12.0 resolution: "retry@npm:0.12.0" @@ -19030,6 +24716,27 @@ __metadata: languageName: node linkType: hard +"rtlcss@npm:^4.1.0": + version: 4.3.0 + resolution: "rtlcss@npm:4.3.0" + dependencies: + escalade: ^3.1.1 + picocolors: ^1.0.0 + postcss: ^8.4.21 + strip-json-comments: ^3.1.1 + bin: + rtlcss: bin/rtlcss.js + checksum: b2e78d01cb15ca7da374681f52d29ea71306166788872242a78ad36afdc4b53e78ee6e33b761744353121b01f65a7209b165b253d2715d313f8f282d4ded62bb + languageName: node + linkType: hard + +"run-applescript@npm:^7.0.0": + version: 7.1.0 + resolution: "run-applescript@npm:7.1.0" + checksum: 8659fb5f2717b2b37a68cbfe5f678254cf24b5a82a6df3372b180c80c7c137dcd757a4166c3887e459f59a090ca414e8ea7ca97cf3ee5123db54b3b4006d7b7a + languageName: node + linkType: hard + "run-parallel@npm:^1.1.9": version: 1.2.0 resolution: "run-parallel@npm:1.2.0" @@ -19152,6 +24859,13 @@ __metadata: languageName: node linkType: hard +"sax@npm:^1.2.4": + version: 1.4.4 + resolution: "sax@npm:1.4.4" + checksum: a6082a153b4ab00968894b3751f6fdc431b0b7edc2d086da67ee162a06716f4bc7d0546e875993e950c757039c9e3838747ab77f50578a6ce579f970a6feadaf + languageName: node + linkType: hard + "sax@npm:~1.2.4": version: 1.2.4 resolution: "sax@npm:1.2.4" @@ -19168,6 +24882,15 @@ __metadata: languageName: node linkType: hard +"scheduler@npm:^0.23.2": + version: 0.23.2 + resolution: "scheduler@npm:0.23.2" + dependencies: + loose-envify: ^1.1.0 + checksum: 3e82d1f419e240ef6219d794ff29c7ee415fbdc19e038f680a10c067108e06284f1847450a210b29bbaf97b9d8a97ced5f624c31c681248ac84c80d56ad5a2c4 + languageName: node + linkType: hard + "scheduler@npm:^0.25.0": version: 0.25.0 resolution: "scheduler@npm:0.25.0" @@ -19175,6 +24898,13 @@ __metadata: languageName: node linkType: hard +"schema-dts@npm:^1.1.2": + version: 1.1.5 + resolution: "schema-dts@npm:1.1.5" + checksum: afca7df65a9d714d4aee367f9ea0e8a5a6f62e212457f240c90ded1ab954499a0e0a21bad097ffc810f03e2ea384985b2c2e08c2eb1cf0ec1780fc15b8b16d3f + languageName: node + linkType: hard + "schema-utils@npm:2.7.0": version: 2.7.0 resolution: "schema-utils@npm:2.7.0" @@ -19208,7 +24938,7 @@ __metadata: languageName: node linkType: hard -"schema-utils@npm:^4.0.0, schema-utils@npm:^4.2.0, schema-utils@npm:^4.3.0, schema-utils@npm:^4.3.3": +"schema-utils@npm:^4.0.0, schema-utils@npm:^4.0.1, schema-utils@npm:^4.2.0, schema-utils@npm:^4.3.0, schema-utils@npm:^4.3.3": version: 4.3.3 resolution: "schema-utils@npm:4.3.3" dependencies: @@ -19220,6 +24950,16 @@ __metadata: languageName: node linkType: hard +"section-matter@npm:^1.0.0": + version: 1.0.0 + resolution: "section-matter@npm:1.0.0" + dependencies: + extend-shallow: ^2.0.1 + kind-of: ^6.0.0 + checksum: 3cc4131705493b2955729b075dcf562359bba66183debb0332752dc9cad35616f6da7a23e42b6cab45cd2e4bb5cda113e9e84c8f05aee77adb6b0289a0229101 + languageName: node + linkType: hard + "select-hose@npm:^2.0.0": version: 2.0.0 resolution: "select-hose@npm:2.0.0" @@ -19237,6 +24977,25 @@ __metadata: languageName: node linkType: hard +"selfsigned@npm:^5.5.0": + version: 5.5.0 + resolution: "selfsigned@npm:5.5.0" + dependencies: + "@peculiar/x509": ^1.14.2 + pkijs: ^3.3.3 + checksum: aa5d61159d3246e3fca3c282cd3304187988dcdea453af284a084f6f49facda475413cc210372e455154a218332b765508e8034959a3bef0beca74145097fe6a + languageName: node + linkType: hard + +"semver-diff@npm:^4.0.0": + version: 4.0.0 + resolution: "semver-diff@npm:4.0.0" + dependencies: + semver: ^7.3.5 + checksum: 4a958d6f76c7e7858268e1e2cf936712542441c9e003e561b574167279eee0a9bd55cc7eae1bfb31d3e7ad06a9fc370e7dd412fcfefec8c0daf1ce5aea623559 + languageName: node + linkType: hard + "semver@npm:^5.6.0, semver@npm:^5.7.1": version: 5.7.2 resolution: "semver@npm:5.7.2" @@ -19333,12 +25092,27 @@ __metadata: languageName: node linkType: hard -"serialize-javascript@npm:^6.0.0, serialize-javascript@npm:^6.0.2": +"serialize-javascript@npm:^6.0.0, serialize-javascript@npm:^6.0.1, serialize-javascript@npm:^6.0.2": version: 6.0.2 resolution: "serialize-javascript@npm:6.0.2" dependencies: - randombytes: ^2.1.0 - checksum: c4839c6206c1d143c0f80763997a361310305751171dd95e4b57efee69b8f6edd8960a0b7fbfc45042aadff98b206d55428aee0dc276efe54f100899c7fa8ab7 + randombytes: ^2.1.0 + checksum: c4839c6206c1d143c0f80763997a361310305751171dd95e4b57efee69b8f6edd8960a0b7fbfc45042aadff98b206d55428aee0dc276efe54f100899c7fa8ab7 + languageName: node + linkType: hard + +"serve-handler@npm:^6.1.6": + version: 6.1.6 + resolution: "serve-handler@npm:6.1.6" + dependencies: + bytes: 3.0.0 + content-disposition: 0.5.2 + mime-types: 2.1.18 + minimatch: 3.1.2 + path-is-inside: 1.0.2 + path-to-regexp: 3.3.0 + range-parser: 1.2.0 + checksum: eb26201e699ac4694fb16f9aaf932330f6b1159e9d9496261baa23caf1e81322afcfd2b5f5f2b306b133298c03a8395a3c13b56fde5d70b331014b3a5ab7217f languageName: node linkType: hard @@ -19439,6 +25213,22 @@ __metadata: languageName: node linkType: hard +"shallow-clone@npm:^3.0.0": + version: 3.0.1 + resolution: "shallow-clone@npm:3.0.1" + dependencies: + kind-of: ^6.0.2 + checksum: 39b3dd9630a774aba288a680e7d2901f5c0eae7b8387fc5c8ea559918b29b3da144b7bdb990d7ccd9e11be05508ac9e459ce51d01fd65e583282f6ffafcba2e7 + languageName: node + linkType: hard + +"shallowequal@npm:^1.1.0": + version: 1.1.0 + resolution: "shallowequal@npm:1.1.0" + checksum: f4c1de0837f106d2dbbfd5d0720a5d059d1c66b42b580965c8f06bb1db684be8783538b684092648c981294bf817869f743a066538771dbecb293df78f765e00 + languageName: node + linkType: hard + "shared@*, shared@1.0.0, shared@workspace:src/shared": version: 0.0.0-use.local resolution: "shared@workspace:src/shared" @@ -19568,6 +25358,17 @@ __metadata: languageName: node linkType: hard +"sirv@npm:^2.0.3": + version: 2.0.4 + resolution: "sirv@npm:2.0.4" + dependencies: + "@polka/url": ^1.0.0-next.24 + mrmime: ^2.0.0 + totalist: ^3.0.0 + checksum: 6853384a51d6ee9377dd657e2b257e0e98b29abbfbfa6333e105197f0f100c8c56a4520b47028b04ab1833cf2312526206f38fcd4f891c6df453f40da1a15a57 + languageName: node + linkType: hard + "sisteransi@npm:^1.0.5": version: 1.0.5 resolution: "sisteransi@npm:1.0.5" @@ -19575,6 +25376,29 @@ __metadata: languageName: node linkType: hard +"sitemap@npm:^7.1.1": + version: 7.1.2 + resolution: "sitemap@npm:7.1.2" + dependencies: + "@types/node": ^17.0.5 + "@types/sax": ^1.2.1 + arg: ^5.0.0 + sax: ^1.2.4 + bin: + sitemap: dist/cli.js + checksum: c6d8e1f06091fdc643f6ed3c13e92215ed1dcbc3bdaf42f50f468a6dc4c6080bd25ffb5f59beb12b4b63f590ad63ab6c285e788d0fade4c811e58bb56a10c6cd + languageName: node + linkType: hard + +"skin-tone@npm:^2.0.0": + version: 2.0.0 + resolution: "skin-tone@npm:2.0.0" + dependencies: + unicode-emoji-modifier-base: ^1.0.0 + checksum: 19de157586b8019cacc55eb25d9d640f00fc02415761f3e41a4527142970fd4e7f6af0333bc90e879858766c20a976107bb386ffd4c812289c01d51f2c8d182c + languageName: node + linkType: hard + "slash@npm:^3.0.0": version: 3.0.0 resolution: "slash@npm:3.0.0" @@ -19649,6 +25473,13 @@ __metadata: languageName: node linkType: hard +"sort-css-media-queries@npm:2.2.0": + version: 2.2.0 + resolution: "sort-css-media-queries@npm:2.2.0" + checksum: c090c9a27be40f3e50f5f9bc9d85a8af0e2c5152565eca34bdb028d952749bce169bc5abef21a5a385ca6221a0869640c9faf58f082ac46de9085ebdb506291f + languageName: node + linkType: hard + "source-list-map@npm:^2.0.0, source-list-map@npm:^2.0.1": version: 2.0.1 resolution: "source-list-map@npm:2.0.1" @@ -19700,7 +25531,7 @@ __metadata: languageName: node linkType: hard -"source-map@npm:^0.7.3": +"source-map@npm:^0.7.0, source-map@npm:^0.7.3": version: 0.7.6 resolution: "source-map@npm:0.7.6" checksum: 932f4a2390aa7100e91357d88cc272de984ad29139ac09eedfde8cc78d46da35f389065d0c5343c5d71d054a6ebd4939a8c0f2c98d5df64fe97bb8a730596c2d @@ -19764,6 +25595,13 @@ __metadata: languageName: node linkType: hard +"srcset@npm:^4.0.0": + version: 4.0.0 + resolution: "srcset@npm:4.0.0" + checksum: aceb898c9281101ef43bfbf96bf04dfae828e1bf942a45df6fad74ae9f8f0a425f4bca1480e0d22879beb40dd2bc6947e0e1e5f4d307a714666196164bc5769d + languageName: node + linkType: hard + "ssri@npm:^13.0.0": version: 13.0.0 resolution: "ssri@npm:13.0.0" @@ -19826,7 +25664,7 @@ __metadata: languageName: node linkType: hard -"std-env@npm:^3.8.0, std-env@npm:^3.9.0": +"std-env@npm:^3.7.0, std-env@npm:^3.8.0, std-env@npm:^3.9.0": version: 3.10.0 resolution: "std-env@npm:3.10.0" checksum: 51d641b36b0fae494a546fb8446d39a837957fbf902c765c62bd12af8e50682d141c4087ca032f1192fa90330c4f6ff23fd6c9795324efacd1684e814471e0e0 @@ -19902,6 +25740,17 @@ __metadata: languageName: node linkType: hard +"string-width@npm:^5.0.1, string-width@npm:^5.1.2": + version: 5.1.2 + resolution: "string-width@npm:5.1.2" + dependencies: + eastasianwidth: ^0.2.0 + emoji-regex: ^9.2.2 + strip-ansi: ^7.0.1 + checksum: 7369deaa29f21dda9a438686154b62c2c5f661f8dda60449088f9f980196f7908fc39fdd1803e3e01541970287cf5deae336798337e9319a7055af89dafa7193 + languageName: node + linkType: hard + "string.prototype.includes@npm:^2.0.1": version: 2.0.1 resolution: "string.prototype.includes@npm:2.0.1" @@ -20039,6 +25888,13 @@ __metadata: languageName: node linkType: hard +"strip-bom-string@npm:^1.0.0": + version: 1.0.0 + resolution: "strip-bom-string@npm:1.0.0" + checksum: 5635a3656d8512a2c194d6c8d5dee7ef0dde6802f7be9413b91e201981ad4132506656d9cf14137f019fd50f0269390d91c7f6a2601b1bee039a4859cfce4934 + languageName: node + linkType: hard + "strip-bom@npm:^3.0.0": version: 3.0.0 resolution: "strip-bom@npm:3.0.0" @@ -20145,6 +26001,18 @@ __metadata: languageName: node linkType: hard +"stylehacks@npm:^6.1.1": + version: 6.1.1 + resolution: "stylehacks@npm:6.1.1" + dependencies: + browserslist: ^4.23.0 + postcss-selector-parser: ^6.0.16 + peerDependencies: + postcss: ^8.4.31 + checksum: 7bef69822280a23817caa43969de76d77ba34042e9f1f7baaeda8f22b1d8c20f1f839ad028552c169e158e387830f176feccd0324b07ef6ec657cba1dd0b2466 + languageName: node + linkType: hard + "stylis@npm:4.2.0": version: 4.2.0 resolution: "stylis@npm:4.2.0" @@ -20242,7 +26110,7 @@ __metadata: languageName: node linkType: hard -"svg-parser@npm:^2.0.2": +"svg-parser@npm:^2.0.2, svg-parser@npm:^2.0.4": version: 2.0.4 resolution: "svg-parser@npm:2.0.4" checksum: b3de6653048212f2ae7afe4a423e04a76ec6d2d06e1bf7eacc618a7c5f7df7faa5105561c57b94579ec831fbbdbf5f190ba56a9205ff39ed13eabdf8ab086ddf @@ -20289,6 +26157,23 @@ __metadata: languageName: node linkType: hard +"svgo@npm:^3.0.2, svgo@npm:^3.2.0": + version: 3.3.2 + resolution: "svgo@npm:3.3.2" + dependencies: + "@trysound/sax": 0.2.0 + commander: ^7.2.0 + css-select: ^5.1.0 + css-tree: ^2.3.1 + css-what: ^6.1.0 + csso: ^5.0.5 + picocolors: ^1.0.0 + bin: + svgo: ./bin/svgo + checksum: a3f8aad597dec13ab24e679c4c218147048dc1414fe04e99447c5f42a6e077b33d712d306df84674b5253b98c9b84dfbfb41fdd08552443b04946e43d03e054e + languageName: node + linkType: hard + "symbol-tree@npm:^3.2.4": version: 3.2.4 resolution: "symbol-tree@npm:3.2.4" @@ -20439,7 +26324,7 @@ __metadata: languageName: node linkType: hard -"terser-webpack-plugin@npm:^5.2.5, terser-webpack-plugin@npm:^5.3.16": +"terser-webpack-plugin@npm:^5.2.5, terser-webpack-plugin@npm:^5.3.16, terser-webpack-plugin@npm:^5.3.9": version: 5.3.16 resolution: "terser-webpack-plugin@npm:5.3.16" dependencies: @@ -20461,7 +26346,7 @@ __metadata: languageName: node linkType: hard -"terser@npm:^5.0.0, terser@npm:^5.10.0, terser@npm:^5.31.1": +"terser@npm:^5.0.0, terser@npm:^5.10.0, terser@npm:^5.15.1, terser@npm:^5.31.1": version: 5.46.0 resolution: "terser@npm:5.46.0" dependencies: @@ -20511,6 +26396,15 @@ __metadata: languageName: node linkType: hard +"thingies@npm:^2.5.0": + version: 2.5.0 + resolution: "thingies@npm:2.5.0" + peerDependencies: + tslib: ^2 + checksum: e73e4bc96aefc41e4f1fdd1cf65eb988c9837f3b5fcd8a472ee30d91c2f7fa9b144562d6b4c5dade6ce70bc5865caf3e869f6d2975cce064b1d81dac3ece3508 + languageName: node + linkType: hard + "throat@npm:^6.0.1": version: 6.0.2 resolution: "throat@npm:6.0.2" @@ -20577,7 +26471,7 @@ __metadata: languageName: node linkType: hard -"tinypool@npm:^1.0.1, tinypool@npm:^1.1.1": +"tinypool@npm:^1.0.1, tinypool@npm:^1.0.2, tinypool@npm:^1.1.1": version: 1.1.1 resolution: "tinypool@npm:1.1.1" checksum: 0258abe108df8be395a2cbdc8b4390c94908850250530f7bea83a129fa33d49a8c93246f76bf81cd458534abd81322f4d4cb3a40690254f8d9044ff449f328a8 @@ -20660,6 +26554,13 @@ __metadata: languageName: node linkType: hard +"totalist@npm:^3.0.0": + version: 3.0.1 + resolution: "totalist@npm:3.0.1" + checksum: 5132d562cf88ff93fd710770a92f31dbe67cc19b5c6ccae2efc0da327f0954d211bbfd9456389655d726c624f284b4a23112f56d1da931ca7cfabbe1f45e778a + languageName: node + linkType: hard + "touch@npm:^3.1.0": version: 3.1.1 resolution: "touch@npm:3.1.1" @@ -20715,6 +26616,15 @@ __metadata: languageName: node linkType: hard +"tree-dump@npm:^1.0.3, tree-dump@npm:^1.1.0": + version: 1.1.0 + resolution: "tree-dump@npm:1.1.0" + peerDependencies: + tslib: 2 + checksum: 5f6fcd1b81b0fa7c638ff43cfbd1b62738c318ac14b0c8e439b1bcca353afe90785c075e9262ee18e50a863eae2eaa919ecfc8f22a4d347a0ea4b02ba088c8c0 + languageName: node + linkType: hard + "tree-kill@npm:1.2.2": version: 1.2.2 resolution: "tree-kill@npm:1.2.2" @@ -20831,14 +26741,14 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^1.11.1, tslib@npm:^1.8.1": +"tslib@npm:^1.11.1, tslib@npm:^1.8.1, tslib@npm:^1.9.3": version: 1.14.1 resolution: "tslib@npm:1.14.1" checksum: dbe628ef87f66691d5d2959b3e41b9ca0045c3ee3c7c7b906cc1e328b39f199bb1ad9e671c39025bd56122ac57dfbf7385a94843b1cc07c60a4db74795829acd languageName: node linkType: hard -"tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.6.2": +"tslib@npm:^2.0.0, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.6.0, tslib@npm:^2.6.2, tslib@npm:^2.8.1": version: 2.8.1 resolution: "tslib@npm:2.8.1" checksum: e4aba30e632b8c8902b47587fd13345e2827fa639e7c3121074d5ee0880723282411a8838f830b55100cbe4517672f84a2472667d355b81e8af165a55dc6203a @@ -20879,6 +26789,15 @@ __metadata: languageName: node linkType: hard +"tsyringe@npm:^4.10.0": + version: 4.10.0 + resolution: "tsyringe@npm:4.10.0" + dependencies: + tslib: ^1.9.3 + checksum: 61810b1bca8bd58911fe54fbb5a660a3d9349ce1b62b5bc33fea82bbd0dc6475b57aa1f4fd95007cf7dd2c9d05502525b65bd900941fc4b3de08f9c56751d5e9 + languageName: node + linkType: hard + "tunnel-agent@npm:^0.6.0": version: 0.6.0 resolution: "tunnel-agent@npm:0.6.0" @@ -20934,7 +26853,14 @@ __metadata: languageName: node linkType: hard -"type-fest@npm:^2.19.0": +"type-fest@npm:^1.0.1": + version: 1.4.0 + resolution: "type-fest@npm:1.4.0" + checksum: b011c3388665b097ae6a109a437a04d6f61d81b7357f74cbcb02246f2f5bd72b888ae33631b99871388122ba0a87f4ff1c94078e7119ff22c70e52c0ff828201 + languageName: node + linkType: hard + +"type-fest@npm:^2.13.0, type-fest@npm:^2.19.0, type-fest@npm:^2.5.0": version: 2.19.0 resolution: "type-fest@npm:2.19.0" checksum: a4ef07ece297c9fba78fc1bd6d85dff4472fe043ede98bd4710d2615d15776902b595abf62bd78339ed6278f021235fb28a96361f8be86ed754f778973a0d278 @@ -21157,6 +27083,13 @@ __metadata: languageName: node linkType: hard +"unicode-emoji-modifier-base@npm:^1.0.0": + version: 1.0.0 + resolution: "unicode-emoji-modifier-base@npm:1.0.0" + checksum: 6e1521d35fa69493207eb8b41f8edb95985d8b3faf07c01d820a1830b5e8403e20002563e2f84683e8e962a49beccae789f0879356bf92a4ec7a4dd8e2d16fdb + languageName: node + linkType: hard + "unicode-match-property-ecmascript@npm:^2.0.0": version: 2.0.0 resolution: "unicode-match-property-ecmascript@npm:2.0.0" @@ -21181,7 +27114,7 @@ __metadata: languageName: node linkType: hard -"unified@npm:^11.0.0": +"unified@npm:^11.0.0, unified@npm:^11.0.3, unified@npm:^11.0.4": version: 11.0.5 resolution: "unified@npm:11.0.5" dependencies: @@ -21223,6 +27156,15 @@ __metadata: languageName: node linkType: hard +"unique-string@npm:^3.0.0": + version: 3.0.0 + resolution: "unique-string@npm:3.0.0" + dependencies: + crypto-random-string: ^4.0.0 + checksum: 1a1e2e7d02eab1bb10f720475da735e1990c8a5ff34edd1a3b6bc31590cb4210b7a1233d779360cc622ce11c211e43afa1628dd658f35d3e6a89964b622940df + languageName: node + linkType: hard + "unist-util-is@npm:^6.0.0": version: 6.0.1 resolution: "unist-util-is@npm:6.0.1" @@ -21232,6 +27174,15 @@ __metadata: languageName: node linkType: hard +"unist-util-position-from-estree@npm:^2.0.0": + version: 2.0.0 + resolution: "unist-util-position-from-estree@npm:2.0.0" + dependencies: + "@types/unist": ^3.0.0 + checksum: d3b3048a5727c2367f64ef6dcc5b20c4717215ef8b1372ff9a7c426297c5d1e5776409938acd01531213e2cd2543218d16e73f9f862f318e9496e2c73bb18354 + languageName: node + linkType: hard + "unist-util-position@npm:^5.0.0": version: 5.0.0 resolution: "unist-util-position@npm:5.0.0" @@ -21337,6 +27288,28 @@ __metadata: languageName: node linkType: hard +"update-notifier@npm:^6.0.2": + version: 6.0.2 + resolution: "update-notifier@npm:6.0.2" + dependencies: + boxen: ^7.0.0 + chalk: ^5.0.1 + configstore: ^6.0.0 + has-yarn: ^3.0.0 + import-lazy: ^4.0.0 + is-ci: ^3.0.1 + is-installed-globally: ^0.4.0 + is-npm: ^6.0.0 + is-yarn-global: ^0.4.0 + latest-version: ^7.0.0 + pupa: ^3.1.0 + semver: ^7.3.7 + semver-diff: ^4.0.0 + xdg-basedir: ^5.1.0 + checksum: 4bae7b3eca7b2068b6b87dde88c9dad24831fa913a5b83ecb39a7e4702c93e8b05fd9bcac5f1a005178f6e5dc859e0b3817ddda833d2a7ab92c6485e078b3cc8 + languageName: node + linkType: hard + "upper-case-first@npm:^2.0.2": version: 2.0.2 resolution: "upper-case-first@npm:2.0.2" @@ -21364,6 +27337,23 @@ __metadata: languageName: node linkType: hard +"url-loader@npm:^4.1.1": + version: 4.1.1 + resolution: "url-loader@npm:4.1.1" + dependencies: + loader-utils: ^2.0.0 + mime-types: ^2.1.27 + schema-utils: ^3.0.0 + peerDependencies: + file-loader: "*" + webpack: ^4.0.0 || ^5.0.0 + peerDependenciesMeta: + file-loader: + optional: true + checksum: c1122a992c6cff70a7e56dfc2b7474534d48eb40b2cc75467cde0c6972e7597faf8e43acb4f45f93c2473645dfd803bcbc20960b57544dd1e4c96e77f72ba6fd + languageName: node + linkType: hard + "url-parse@npm:^1.5.3": version: 1.5.10 resolution: "url-parse@npm:1.5.10" @@ -21425,6 +27415,13 @@ __metadata: languageName: node linkType: hard +"utility-types@npm:^3.10.0": + version: 3.11.0 + resolution: "utility-types@npm:3.11.0" + checksum: 35a4866927bbea5d037726744028d05c6e37772ded2aabaca21480ce9380185436aef586ead525e327c7f3c640b1a3287769a12ef269c7b165a2ddd50ea6ad61 + languageName: node + linkType: hard + "utils-merge@npm:1.0.1": version: 1.0.1 resolution: "utils-merge@npm:1.0.1" @@ -21505,6 +27502,16 @@ __metadata: languageName: node linkType: hard +"vfile-location@npm:^5.0.0": + version: 5.0.3 + resolution: "vfile-location@npm:5.0.3" + dependencies: + "@types/unist": ^3.0.0 + vfile: ^6.0.0 + checksum: bfb3821b6981b6e9aa369bed67a40090b800562064ea312e84437762562df3225a0ca922695389cc0ef1e115f19476c363f53e3ed44dec17c50678b7670b5f2b + languageName: node + linkType: hard + "vfile-message@npm:^4.0.0": version: 4.0.3 resolution: "vfile-message@npm:4.0.3" @@ -21515,7 +27522,7 @@ __metadata: languageName: node linkType: hard -"vfile@npm:^6.0.0": +"vfile@npm:^6.0.0, vfile@npm:^6.0.1": version: 6.0.3 resolution: "vfile@npm:6.0.3" dependencies: @@ -21869,7 +27876,7 @@ __metadata: languageName: node linkType: hard -"watchpack@npm:^2.4.4": +"watchpack@npm:^2.4.4, watchpack@npm:^2.5.1": version: 2.5.1 resolution: "watchpack@npm:2.5.1" dependencies: @@ -21888,6 +27895,13 @@ __metadata: languageName: node linkType: hard +"web-namespaces@npm:^2.0.0": + version: 2.0.1 + resolution: "web-namespaces@npm:2.0.1" + checksum: b6d9f02f1a43d0ef0848a812d89c83801d5bbad57d8bb61f02eb6d7eb794c3736f6cc2e1191664bb26136594c8218ac609f4069722c6f56d9fc2d808fa9271c6 + languageName: node + linkType: hard + "web-vitals@npm:^4.2.4": version: 4.2.4 resolution: "web-vitals@npm:4.2.4" @@ -21923,6 +27937,28 @@ __metadata: languageName: node linkType: hard +"webpack-bundle-analyzer@npm:^4.10.2": + version: 4.10.2 + resolution: "webpack-bundle-analyzer@npm:4.10.2" + dependencies: + "@discoveryjs/json-ext": 0.5.7 + acorn: ^8.0.4 + acorn-walk: ^8.0.0 + commander: ^7.2.0 + debounce: ^1.2.1 + escape-string-regexp: ^4.0.0 + gzip-size: ^6.0.0 + html-escaper: ^2.0.2 + opener: ^1.5.2 + picocolors: ^1.0.0 + sirv: ^2.0.3 + ws: ^7.3.1 + bin: + webpack-bundle-analyzer: lib/bin/analyzer.js + checksum: 4f0275e7d87bb6203a618ca5d2d4953943979d986fa2b91be1bf1ad0bcd22bec13398803273d11699f9fbcf106896311208a72d63fe5f8a47b687a226e598dc1 + languageName: node + linkType: hard + "webpack-dev-middleware@npm:^5.3.4": version: 5.3.4 resolution: "webpack-dev-middleware@npm:5.3.4" @@ -21938,6 +27974,25 @@ __metadata: languageName: node linkType: hard +"webpack-dev-middleware@npm:^7.4.2": + version: 7.4.5 + resolution: "webpack-dev-middleware@npm:7.4.5" + dependencies: + colorette: ^2.0.10 + memfs: ^4.43.1 + mime-types: ^3.0.1 + on-finished: ^2.4.1 + range-parser: ^1.2.1 + schema-utils: ^4.0.0 + peerDependencies: + webpack: ^5.0.0 + peerDependenciesMeta: + webpack: + optional: true + checksum: 54c31f757fec48822c37129ba166f21985ad61a5971655e3c3b7358d997975587687d40dc6c1194f4e54615bd0916df15e4ebc3e3b5203300a52038eaeed5c0b + languageName: node + linkType: hard + "webpack-dev-server@npm:^4.6.0": version: 4.15.2 resolution: "webpack-dev-server@npm:4.15.2" @@ -21985,6 +28040,51 @@ __metadata: languageName: node linkType: hard +"webpack-dev-server@npm:^5.2.2": + version: 5.2.3 + resolution: "webpack-dev-server@npm:5.2.3" + dependencies: + "@types/bonjour": ^3.5.13 + "@types/connect-history-api-fallback": ^1.5.4 + "@types/express": ^4.17.25 + "@types/express-serve-static-core": ^4.17.21 + "@types/serve-index": ^1.9.4 + "@types/serve-static": ^1.15.5 + "@types/sockjs": ^0.3.36 + "@types/ws": ^8.5.10 + ansi-html-community: ^0.0.8 + bonjour-service: ^1.2.1 + chokidar: ^3.6.0 + colorette: ^2.0.10 + compression: ^1.8.1 + connect-history-api-fallback: ^2.0.0 + express: ^4.22.1 + graceful-fs: ^4.2.6 + http-proxy-middleware: ^2.0.9 + ipaddr.js: ^2.1.0 + launch-editor: ^2.6.1 + open: ^10.0.3 + p-retry: ^6.2.0 + schema-utils: ^4.2.0 + selfsigned: ^5.5.0 + serve-index: ^1.9.1 + sockjs: ^0.3.24 + spdy: ^4.0.2 + webpack-dev-middleware: ^7.4.2 + ws: ^8.18.0 + peerDependencies: + webpack: ^5.0.0 + peerDependenciesMeta: + webpack: + optional: true + webpack-cli: + optional: true + bin: + webpack-dev-server: bin/webpack-dev-server.js + checksum: 2b7f2096529945f578e86966d9a0994b0a87b82e3bb3a7cd1ccea2fb81aa95724473a88c9b2033ae3d2f799d13330342948ea77638029d10c8c0c746aac545f7 + languageName: node + linkType: hard + "webpack-manifest-plugin@npm:^4.0.2": version: 4.1.1 resolution: "webpack-manifest-plugin@npm:4.1.1" @@ -21997,6 +28097,28 @@ __metadata: languageName: node linkType: hard +"webpack-merge@npm:^5.9.0": + version: 5.10.0 + resolution: "webpack-merge@npm:5.10.0" + dependencies: + clone-deep: ^4.0.1 + flat: ^5.0.2 + wildcard: ^2.0.0 + checksum: 1fe8bf5309add7298e1ac72fb3f2090e1dfa80c48c7e79fa48aa60b5961332c7d0d61efa8851acb805e6b91a4584537a347bc106e05e9aec87fa4f7088c62f2f + languageName: node + linkType: hard + +"webpack-merge@npm:^6.0.1": + version: 6.0.1 + resolution: "webpack-merge@npm:6.0.1" + dependencies: + clone-deep: ^4.0.1 + flat: ^5.0.2 + wildcard: ^2.0.1 + checksum: e8a604c686b944605a1c57cc7b75e886ab902dc5ffdd15259a092c5c2dd5f58868fe39f995ea4bad4f189e38843b061c4ae1eb22822d7169813f4adab571dc3d + languageName: node + linkType: hard + "webpack-sources@npm:^1.4.3": version: 1.4.3 resolution: "webpack-sources@npm:1.4.3" @@ -22062,6 +28184,62 @@ __metadata: languageName: node linkType: hard +"webpack@npm:^5.88.1, webpack@npm:^5.95.0": + version: 5.105.2 + resolution: "webpack@npm:5.105.2" + dependencies: + "@types/eslint-scope": ^3.7.7 + "@types/estree": ^1.0.8 + "@types/json-schema": ^7.0.15 + "@webassemblyjs/ast": ^1.14.1 + "@webassemblyjs/wasm-edit": ^1.14.1 + "@webassemblyjs/wasm-parser": ^1.14.1 + acorn: ^8.15.0 + acorn-import-phases: ^1.0.3 + browserslist: ^4.28.1 + chrome-trace-event: ^1.0.2 + enhanced-resolve: ^5.19.0 + es-module-lexer: ^2.0.0 + eslint-scope: 5.1.1 + events: ^3.2.0 + glob-to-regexp: ^0.4.1 + graceful-fs: ^4.2.11 + json-parse-even-better-errors: ^2.3.1 + loader-runner: ^4.3.1 + mime-types: ^2.1.27 + neo-async: ^2.6.2 + schema-utils: ^4.3.3 + tapable: ^2.3.0 + terser-webpack-plugin: ^5.3.16 + watchpack: ^2.5.1 + webpack-sources: ^3.3.3 + peerDependenciesMeta: + webpack-cli: + optional: true + bin: + webpack: bin/webpack.js + checksum: c5568f6d54fedadadc61d09e72e9eddd1aea7b2ac9ff80355c1107a2305efd82a6de508383da2b0c065a86e4c3d748d2e1ae666274afccda9c5774a7f5993fed + languageName: node + linkType: hard + +"webpackbar@npm:^6.0.1": + version: 6.0.1 + resolution: "webpackbar@npm:6.0.1" + dependencies: + ansi-escapes: ^4.3.2 + chalk: ^4.1.2 + consola: ^3.2.3 + figures: ^3.2.0 + markdown-table: ^2.0.0 + pretty-time: ^1.1.0 + std-env: ^3.7.0 + wrap-ansi: ^7.0.0 + peerDependencies: + webpack: 3 || 4 || 5 + checksum: e9ba314452486230668ab34aea7c3494866dbe29e327e9201551a839000ee7e878d8a47b8977acb76ec9443b4257dfcdb05bae9bbc27ffb21793d2bed7907687 + languageName: node + linkType: hard + "websocket-driver@npm:>=0.5.1, websocket-driver@npm:^0.7.4": version: 0.7.4 resolution: "websocket-driver@npm:0.7.4" @@ -22248,6 +28426,22 @@ __metadata: languageName: node linkType: hard +"widest-line@npm:^4.0.1": + version: 4.0.1 + resolution: "widest-line@npm:4.0.1" + dependencies: + string-width: ^5.0.1 + checksum: 64c48cf27171221be5f86fc54b94dd29879165bdff1a7aa92dde723d9a8c99fb108312768a5d62c8c2b80b701fa27bbd36a1ddc58367585cd45c0db7920a0cba + languageName: node + linkType: hard + +"wildcard@npm:^2.0.0, wildcard@npm:^2.0.1": + version: 2.0.1 + resolution: "wildcard@npm:2.0.1" + checksum: e0c60a12a219e4b12065d1199802d81c27b841ed6ad6d9d28240980c73ceec6f856771d575af367cbec2982d9ae7838759168b551776577f155044f5a5ba843c + languageName: node + linkType: hard + "word-wrap@npm:^1.2.5, word-wrap@npm:~1.2.3": version: 1.2.5 resolution: "word-wrap@npm:1.2.5" @@ -22482,6 +28676,17 @@ __metadata: languageName: node linkType: hard +"wrap-ansi@npm:^8.0.1, wrap-ansi@npm:^8.1.0": + version: 8.1.0 + resolution: "wrap-ansi@npm:8.1.0" + dependencies: + ansi-styles: ^6.1.0 + string-width: ^5.0.1 + strip-ansi: ^7.0.1 + checksum: 371733296dc2d616900ce15a0049dca0ef67597d6394c57347ba334393599e800bab03c41d4d45221b6bc967b8c453ec3ae4749eff3894202d16800fdfe0e238 + languageName: node + linkType: hard + "wrappy@npm:1": version: 1.0.2 resolution: "wrappy@npm:1.0.2" @@ -22489,7 +28694,7 @@ __metadata: languageName: node linkType: hard -"write-file-atomic@npm:^3.0.0": +"write-file-atomic@npm:^3.0.0, write-file-atomic@npm:^3.0.3": version: 3.0.3 resolution: "write-file-atomic@npm:3.0.3" dependencies: @@ -22501,7 +28706,7 @@ __metadata: languageName: node linkType: hard -"ws@npm:^7.4.6": +"ws@npm:^7.3.1, ws@npm:^7.4.6": version: 7.5.10 resolution: "ws@npm:7.5.10" peerDependencies: @@ -22516,7 +28721,7 @@ __metadata: languageName: node linkType: hard -"ws@npm:^8.13.0": +"ws@npm:^8.13.0, ws@npm:^8.18.0": version: 8.19.0 resolution: "ws@npm:8.19.0" peerDependencies: @@ -22531,6 +28736,33 @@ __metadata: languageName: node linkType: hard +"wsl-utils@npm:^0.1.0": + version: 0.1.0 + resolution: "wsl-utils@npm:0.1.0" + dependencies: + is-wsl: ^3.1.0 + checksum: de4c92187e04c3c27b4478f410a02e81c351dc85efa3447bf1666f34fc80baacd890a6698ec91995631714086992036013286aea3d77e6974020d40a08e00aec + languageName: node + linkType: hard + +"xdg-basedir@npm:^5.0.1, xdg-basedir@npm:^5.1.0": + version: 5.1.0 + resolution: "xdg-basedir@npm:5.1.0" + checksum: b60e8a2c663ccb1dac77c2d913f3b96de48dafbfa083657171d3d50e10820b8a04bb4edfe9f00808c8c20e5f5355e1927bea9029f03136e29265cb98291e1fea + languageName: node + linkType: hard + +"xml-js@npm:^1.6.11": + version: 1.6.11 + resolution: "xml-js@npm:1.6.11" + dependencies: + sax: ^1.2.4 + bin: + xml-js: ./bin/cli.js + checksum: 24a55479919413687105fc2d8ab05e613ebedb1c1bc12258a108e07cff5ef793779297db854800a4edf0281303ebd1f177bc4a588442f5344e62b3dddda26c2b + languageName: node + linkType: hard + "xml-name-validator@npm:^3.0.0": version: 3.0.0 resolution: "xml-name-validator@npm:3.0.0" @@ -22681,6 +28913,13 @@ __metadata: languageName: node linkType: hard +"yocto-queue@npm:^1.0.0": + version: 1.2.2 + resolution: "yocto-queue@npm:1.2.2" + checksum: 92dd9880c324dbc94ff4b677b7d350ba8d835619062b7102f577add7a59ab4d87f40edc5a03d77d369dfa9d11175b1b2ec4a06a6f8a5d8ce5d1306713f66ee41 + languageName: node + linkType: hard + "yoctocolors-cjs@npm:^2.1.3": version: 2.1.3 resolution: "yoctocolors-cjs@npm:2.1.3" From 44c9143cfa8b030d7ac979b9a8afefef71befa86 Mon Sep 17 00:00:00 2001 From: Raphael Bessin Date: Tue, 24 Feb 2026 18:15:44 -0500 Subject: [PATCH 2/3] formatting changes --- .../backend-endpoints/SKILL.md | 379 ----------- .../general-practices/frontend-forms/SKILL.md | 600 ----------------- .../frontend-hooks-and-apis/SKILL.md | 469 ------------- .../postman-api-testing/SKILL.md | 320 --------- .../prisma-schema-shared-types/SKILL.md | 620 ------------------ .../query-args-and-transformers/SKILL.md | 493 -------------- .../react-components/SKILL.md | 546 --------------- .../repository-overview/SKILL.md | 350 ---------- docs-site/README.md | 1 + docs-site/babel.config.js | 2 +- .../general-practices/backend-endpoints.md | 140 ++-- .../query-args-and-transformers.md | 91 +-- .../general-practices/repository-overview.md | 43 +- docs-site/docusaurus.config.js | 37 +- docs-site/scripts/generate-sidebar.js | 2 +- docs-site/scripts/sync-skills.js | 12 +- 16 files changed, 141 insertions(+), 3964 deletions(-) delete mode 100644 .claude/skills/general-practices/backend-endpoints/SKILL.md delete mode 100644 .claude/skills/general-practices/frontend-forms/SKILL.md delete mode 100644 .claude/skills/general-practices/frontend-hooks-and-apis/SKILL.md delete mode 100644 .claude/skills/general-practices/postman-api-testing/SKILL.md delete mode 100644 .claude/skills/general-practices/prisma-schema-shared-types/SKILL.md delete mode 100644 .claude/skills/general-practices/query-args-and-transformers/SKILL.md delete mode 100644 .claude/skills/general-practices/react-components/SKILL.md delete mode 100644 .claude/skills/general-practices/repository-overview/SKILL.md diff --git a/.claude/skills/general-practices/backend-endpoints/SKILL.md b/.claude/skills/general-practices/backend-endpoints/SKILL.md deleted file mode 100644 index de2b24aa87..0000000000 --- a/.claude/skills/general-practices/backend-endpoints/SKILL.md +++ /dev/null @@ -1,379 +0,0 @@ ---- -name: backend-endpoints -description: Guide for creating backend API endpoints in FinishLine following the Route → Controller → Service pattern with multi-tenant security. Use when creating new endpoints, adding API routes, implementing controllers or services, building backend request handlers, or when asked how the backend works. ---- - -# Backend Endpoints - -> **Summary:** Every backend endpoint in FinishLine follows a three-layer pattern: Route (validation) → Controller (request extraction) → Service (business logic). This skill walks through the full pattern and how to add a new endpoint from scratch. - -## Overview - -FinishLine's backend is an Express.js application written in TypeScript. All request handling is split into three distinct layers with clear responsibilities: - -1. **Routes** define the HTTP method and path, declare validation rules using `express-validator`, and point to a controller method. -2. **Controllers** are lightweight wrappers around the service functions. They extract data from `req.params`, `req.body`, and `req.query`, call the appropriate service method, and return the result as JSON. They also catch service errors and delegate to Express via `next(error)`. -3. **Services** contain all business logic: permission checks, database queries via Prisma, data transformation, and side effects (Slack notifications, Google integrations, etc.). Services throw custom exceptions when something goes wrong. - -Two key objects are available on every request from middleware: `req.currentUser` (the authenticated `User`) and `req.organization` (the Prisma `Organization` record). These are set by the `getUserAndOrganization` middleware in `src/backend/index.ts` and typed via `src/backend/custom.d.ts`. - -## Architecture - -``` - Client Request - │ - ▼ -┌──────────────┐ JWT validated, user -│ Middleware │ and organization -│ (global) │ attached to req -└──────┬───────┘ - │ - ▼ -┌──────────────┐ express-validator -│ Route │ rules, then -│ │ validateInputs -└──────┬───────┘ - │ - ▼ -┌──────────────┐ Extract params/body, -│ Controller │ call service, return -│ (thin) │ JSON, pass errors -│ │ to next() -└──────┬───────┘ - │ - ▼ -┌──────────────┐ Permission checks, -│ Service │ Prisma queries, -│ │ transformers, -│ │ side effects -└──────┬───────┘ - │ - ▼ -┌──────────────┐ -│ Prisma DB │ -└──────────────┘ -``` - -If a service throws an exception, it bubbles up through the controller's `next(error)` call and is caught by the global `errorHandler` middleware registered at the bottom of `src/backend/index.ts`. - -## File Structure - -Finishline uses a layer-based architecture, where 3 folders (routes, controllers, services) contain all the files related to that layer for every domain. The naming convention looks like: - -- `src/backend/src/routes/{feature}.routes.ts` -- `src/backend/src/controllers/{feature}.controllers.ts` -- `src/backend/src/services/{feature}.services.ts` - -## How Endpoint URLs Work - -The full URL path for any endpoint is the **combination** of the base path registered in `src/backend/index.ts` and the route path in the router file. This is a very common source of confusion. - -For example, if `index.ts` registers: - -```typescript -app.use('/calendar', calendarRouter); -``` - -And the router defines: - -```typescript -calendarRouter.post('/shop/create', ...); -``` - -Then the actual endpoint URL is `POST /calendar/shop/create`. The base path `/calendar` comes from `index.ts`, and `/shop/create` comes from the route file. Always mentally concatenate these two when figuring out or defining an endpoint's URL. - -## Step-by-Step: Adding a New Endpoint - -This walkthrough adds a hypothetical `POST /calendar/shop/create` endpoint. - -### Step 1: Define the Route - -Add validation rules using `express-validator` and the helpers from `validation.utils.ts`. Always end the chain with `validateInputs` before the controller method. - -```typescript -// src/backend/src/routes/calendar.routes.ts -import express from 'express'; -import { body } from 'express-validator'; -import { nonEmptyString, isDate, validateInputs } from '../utils/validation.utils.js'; -import CalendarController from '../controllers/calendar.controllers.js'; - -const calendarRouter = express.Router(); - -calendarRouter.post( - '/shop/create', - nonEmptyString(body('name')), - nonEmptyString(body('description')), - isDate(body('dateEstablished')), - validateInputs, - CalendarController.createShop -); - -export default calendarRouter; -``` - -**Key rules for routes:** - -- Use `GET` for all read operations. Use `POST` for all mutations (create, edit, delete). NEVER use `PUT`, `PATCH`, or `DELETE` HTTP methods. -- Delete endpoints follow the pattern `POST '/{entity}/:id/delete'`. -- Always call `validateInputs` as the last middleware before the controller. -- Use the shared validation helpers (`nonEmptyString`, `intMinZero`, `isDate`, etc.) instead of writing raw `express-validator` chains. -- For array fields, validate both the array and its items: `body('ids').isArray()` then `body('ids.*').isString()`. -- URL params use `param()`, query strings use `query()`, body fields use `body()`. - -**When to abstract validators:** Keep validation inline in the route by default. Only extract validators into `validation.utils.ts` when: - -- The request body contains a **nested object** that is itself a known entity (e.g., a work package embedded inside a project create payload). Create a named validator array like `workPackageProposedChangesValidators`. -- The **same set of validations** is repeated across multiple routes (e.g., `descriptionBulletsValidators` used in both work package and project routes). - -For a simple endpoint with a few string/number/date fields, just write the validators inline. - -### Step 2: Register the Router (if new feature) - -If creating a brand new feature router, register it in `src/backend/index.ts`: - -```typescript -// src/backend/index.ts -import calendarRouter from './src/routes/calendar.routes.js'; - -// ... after getUserAndOrganization middleware ... -app.use('/calendar', calendarRouter); -``` - -Remember: the full endpoint URL is `index.ts` base path + route path = `POST /calendar/shop/create`. - -### Step 3: Write the Controller Method - -Controllers follow a rigid structure: try/catch, extract request data, call service, return JSON, pass errors to `next`. - -```typescript -// src/backend/src/controllers/calendar.controllers.ts -import { NextFunction, Request, Response } from 'express'; -import CalendarService from '../services/calendar.services.js'; - -export default class CalendarController { - static async createShop(req: Request, res: Response, next: NextFunction) { - try { - const { name, description, dateEstablished } = req.body; - - // Parse date strings to Date objects - // before passing to the service - const parsedDate = new Date(dateEstablished); - - const shop = await CalendarService.createShop(req.currentUser, name, description, parsedDate, req.organization); - - res.status(200).json(shop); - } catch (error: unknown) { - next(error); - } - } -} -``` - -**Key rules for controllers:** - -- Every method MUST be `static async` with signature `(req: Request, res: Response, next: NextFunction)`. -- Every method body MUST be wrapped in `try { ... } catch (error: unknown) { next(error); }`. -- Extract URL params with: `const { id } = req.params as Record;` -- **Parse date strings to `Date` objects in the controller** before passing to the service: `new Date(startTime)`. -- Pass `req.currentUser` and `req.organization` to service methods that need them. -- Return `res.status(200).json(result)` for all successful responses. - -### Step 4: Write the Service Method - -Services contain all business logic. - -```typescript -// src/backend/src/services/calendar.services.ts -import { User, Shop, notGuest } from 'shared'; -import prisma from '../prisma/prisma.js'; -import { AccessDeniedGuestException, HttpException } from '../utils/errors.utils.js'; -import { shopTransformer } from '../transformers/calendar.transformer.js'; -import { getShopQueryArgs } from '../prisma-query-args/shop.query-args.js'; -import { userHasPermission } from '../utils/users.utils.js'; -import { Organization } from '@prisma/client'; - -export default class CalendarService { - /** - * Creates a new shop. - * - * @param submitter the user creating the shop - * @param name the name of the shop - * @param description a description of the shop - * @param dateEstablished when the shop was set up - * @param organization the current organization - * @returns the created Shop - * @throws AccessDeniedGuestException if the - * submitter is a guest - * @throws HttpException if a shop with the same - * name already exists - */ - static async createShop( - submitter: User, - name: string, - description: string, - dateEstablished: Date, - organization: Organization - ): Promise { - // 1. Permission check - if (!(await userHasPermission(submitter.userId, organization.organizationId, notGuest))) { - throw new AccessDeniedGuestException('create shops'); - } - - // 2. Business rule validation (inline select) - const duplicate = await prisma.shop.findFirst({ - where: { - organizationId: organization.organizationId, - dateDeleted: null, - name: { equals: name, mode: 'insensitive' } - }, - select: { shopId: true } - }); - - if (duplicate) { - throw new HttpException(400, 'A shop with that name already exists'); - } - - // 3. Database write (query args for response) - const created = await prisma.shop.create({ - data: { - name, - description, - dateEstablished, - organizationId: organization.organizationId, - userCreatedId: submitter.userId - }, - ...getShopQueryArgs(organization.organizationId) - }); - - // 4. Transform and return - return shopTransformer(created); - } -} -``` - -**Key rules for services:** - -- Every method MUST be `static async`. -- Every mutation method MUST accept `submitter: User` and `organization: Organization`. -- Every read method MUST accept `organization: Organization` and filter by `organization.organizationId`. -- NEVER return raw Prisma objects. Always pass results through a transformer. -- Throw custom exceptions from `errors.utils.ts` — never throw plain `Error` objects. -- Add JSDoc comments with `@param`, `@returns`, and `@throws` tags. -- Multiple database writes MUST be wrapped in `prisma.$transaction()`. -- Check permissions early, before any database writes. -- ALWAYS filter `dateDeleted: null` on queries at both the top level and within nested includes/selects. -- Deleting an entity MUST be a soft delete (`dateDeleted: new Date()`), never `prisma.*.delete()`. - -For query args and transformer patterns, see the [query-args-and-transformers](../query-args-and-transformers/SKILL.md) document. - -### Step 5: Deciding the Access Level - -Every write endpoint (and some sensitive reads) needs a permission check at the top of the service method. Use `userHasPermission` with the appropriate check function from `shared`: - -```typescript -import { - notGuest, // members and above - isLeadership, // leads and above - isHead, // heads and above - isAdmin // admins and app-admins only -} from 'shared'; - -if ( - !(await userHasPermission( - submitter.userId, - organization.organizationId, - isHead // choose the right level - )) -) { - throw new AccessDeniedAdminOnlyException('create event types'); -} -``` - -**How to choose the right level:** - -The role hierarchy from lowest to highest is: Guest → Member → Leadership (leads) → Head → Admin → App Admin. - -- **`notGuest` (members and up):** Most create operations on everyday entities. Members should be able to create things they interact with regularly (e.g., reimbursement requests, schedule confirmations, tasks). All writes should be at least this level — guests NEVER mutate data. -- **`isLeadership` (leads and up):** Creating higher-level entities and editing things the user created. Leads should be able to create basically anything, and edit their own creations. -- **`isHead` (heads and up):** Creating and editing general organizational objects not attached to a specific user (e.g., event types, calendars, shops, machinery). -- **`isAdmin` (admins only):** Org-wide configuration or destructive operations (e.g., deleting event types, managing organization settings, creating projects or work packages without a change request). - -Match the exception class to the level: `AccessDeniedGuestException` for `notGuest`, `AccessDeniedMemberException` for `isLeadership`, `AccessDeniedException` with a descriptive message for `isHead`, `AccessDeniedAdminOnlyException` for `isAdmin`. - -## Error Handling - -Services throw exceptions from `src/backend/src/utils/errors.utils.ts`. The global `errorHandler` middleware catches them. The `name` parameter for `NotFoundException` and `DeletedException` MUST be one of the values in the `ExceptionObjectNames` type union in `errors.utils.ts`. Add your entity to that type if it's not listed. - -## Validation Helpers - -`src/backend/src/utils/validation.utils.ts` provides reusable validation chains: - -| Helper | Validates | -| --------------------------- | ---------------------------- | -| `nonEmptyString(body('x'))` | Non-empty string | -| `intMinZero(body('x'))` | Integer ≥ 0, not a string | -| `decimalMinZero(body('x'))` | Decimal ≥ 0 | -| `isDate(body('x'))` | Parseable date string | -| `isOptionalDate(body('x'))` | Optional parseable date | -| `isRole(body('x'))` | Valid `RoleEnum` value | -| `isStatus(body('x'))` | Valid `WbsElementStatus` | -| `isEventStatus(body('x'))` | Valid `Event_Status` | -| `validateInputs` | Runs validation, returns 400 | - -For complex reusable validators, spread them: `...descriptionBulletsValidators`. - -## Key Rules - -- Every controller method MUST pass errors to `next(error)`. -- Every service method MUST filter by `organization.organizationId`. -- Use `GET` for reads, `POST` for all mutations. NEVER use `PUT`, `PATCH`, or `DELETE`. -- NEVER return raw Prisma objects from services. Always use transformers. -- Multiple database writes MUST be wrapped in `prisma.$transaction()`. -- Service and controller classes use `static` methods — never instantiated. -- Always use `.js` extensions in import paths (NodeNext module resolution). -- Import `prisma` from `../prisma/prisma.js`, never from `@prisma/client` directly. -- ALWAYS filter `dateDeleted: null` at both top level and in nested relations. -- Deleting an entity MUST be a soft delete (`dateDeleted: new Date()`). -- Parse date strings to `Date` objects in the controller. - -## Common Mistakes - -- **Handling errors in the controller** instead of calling `next(error)`. -- **Forgetting `organizationId`** in a Prisma query — leaks data across orgs. -- **Using `PUT` or `DELETE` HTTP methods.** Use `POST` for all mutations. -- **Writing business logic in the controller.** Anything beyond request extraction belongs in the service. -- **Forgetting `validateInputs`** as the last middleware before the controller. -- **Not adding your entity to `ExceptionObjectNames`** when using `NotFoundException` or `DeletedException`. -- **Confusing the endpoint URL.** Full path = `index.ts` base path + route path. -- **Forgetting to parse dates in the controller.** Convert with `new Date()` before passing to the service. -- **Forgetting `dateDeleted: null`** on queries or nested relations. - -## Reference Files - -- `src/backend/src/routes/calendar.routes.ts` — Comprehensive route file with many endpoint types -- `src/backend/src/controllers/calendar.controllers.ts` — Clean controller class with consistent try/catch/next -- `src/backend/src/services/calendar.services.ts` — Full-featured service with permissions, org validation, transactions -- `src/backend/src/utils/errors.utils.ts` — Custom exception classes and global error handler -- `src/backend/src/utils/validation.utils.ts` — Shared validation helpers -- `src/backend/index.ts` — Middleware ordering and route registration -- `src/backend/custom.d.ts` — TypeScript augmentation for `currentUser` and `organization` - -## Checklist - -- [ ] Route uses `GET` for reads, `POST` for mutations -- [ ] All body/param/query fields have validation rules -- [ ] `validateInputs` is the last middleware before the controller -- [ ] Full endpoint URL (index.ts base + route path) is correct -- [ ] Controller is `static async` with `try/catch/next(error)` -- [ ] Controller contains NO business logic -- [ ] Date strings parsed to `Date` objects in the controller -- [ ] Service has appropriate permission check (see access level guide) -- [ ] Service filters `organization.organizationId` on all queries -- [ ] Service throws custom exceptions, not plain `Error` -- [ ] Entity name added to `ExceptionObjectNames` if needed -- [ ] All queries filter `dateDeleted: null` at every level -- [ ] Delete operations are soft deletes -- [ ] Service returns transformed shared types (see [query-args-and-transformers](../query-args-and-transformers/SKILL.md)) -- [ ] Multiple writes wrapped in `prisma.$transaction()` -- [ ] All imports use `.js` extensions -- [ ] Router registered in `index.ts` (if new feature) diff --git a/.claude/skills/general-practices/frontend-forms/SKILL.md b/.claude/skills/general-practices/frontend-forms/SKILL.md deleted file mode 100644 index 0a2c010537..0000000000 --- a/.claude/skills/general-practices/frontend-forms/SKILL.md +++ /dev/null @@ -1,600 +0,0 @@ ---- -name: frontend-forms -description: Guide for building forms in FinishLine using React Hook Form with MUI components and the NERFormModal abstraction. Covers useForm setup, Controller wrapping, create vs edit mode, form-modal reset lifecycle, and shared form field components. Use when creating new forms, adding form fields, building create/edit modals, working with React Hook Form, or debugging form state issues. NEVER use useEffect to sync form state. ---- - -# Frontend Forms - -> **Summary:** FinishLine forms use React Hook Form with Yup validation, MUI -> components wrapped via `Controller`, and the `NERFormModal` component for -> modal-based forms. The parent component owns the mutation; the form just -> calls `onSubmit` with validated data. - -## Overview - -All forms in FinishLine follow a consistent pattern built on three libraries: -React Hook Form for state management, Yup for schema validation, and MUI for -UI components. The key architectural decision is a strict separation between -the **form component** (which handles layout, validation, and data collection) -and the **parent component** (which owns the mutation hook and handles API -calls). - -For modal-based forms (the most common pattern), FinishLine provides -`NERFormModal` — a wrapper around `NERModal` that handles the form element, -submit-then-reset, and reset-on-close lifecycle automatically. For full-page -forms (like the Work Package editor), the form element is rendered directly. - -React Hook Form's `defaultValues` and `reset` function are the **only** -mechanisms for initializing and updating form state. `useEffect` MUST NEVER -be used to synchronize form fields with props, reset forms, or respond to -data changes. - -## Architecture - -### Modal Form Data Flow - -``` -┌──────────────┐ onSubmit ┌──────────────┐ -│ CreateXModal │◀── (data) ──── │ XFormModal │ -│ or EditXModal│ │ (shared form)│ -├──────────────┤ ├──────────────┤ -│ owns mutation│ │ useForm() │ -│ hook │── defaultValues│ Controller │ -│ passes │── onSubmit ──▶ │ Yup schema │ -│ mutateAsync │ │ NERFormModal │ -└──────────────┘ └──────────────┘ - │ - ▼ - React Query - mutation hook -``` - -### Full-Page Form Data Flow - -``` -┌──────────────┐ mutateAsync ┌──────────────┐ -│ CreateXForm │── + schema ───▶│ XFormView │ -│ or EditXForm │ │ │ -├──────────────┤ ├──────────────┤ -│ owns mutation│ │ useForm() │ -│ fetches data │── defaultValues│ tag │ -│ builds schema│── onSubmit ──▶ │ Controller │ -└──────────────┘ └──────────────┘ -``` - -## File Locations - -- **NERFormModal:** `src/frontend/src/components/NERFormModal.tsx` -- **NERModal (base):** `src/frontend/src/components/NERModal.tsx` -- **NERDraggableFormModal:** `src/frontend/src/components/NERDraggableFormModal.tsx` -- **ReactHookTextField:** `src/frontend/src/components/ReactHookTextField.tsx` -- **ReactHookEditableList:** `src/frontend/src/components/ReactHookEditableList.tsx` - -## Core Concepts - -### NERFormModal - -`NERFormModal` wraps `NERModal` and provides automatic form lifecycle -management. It accepts these key props: - -- `reset` — The `reset` function from `useForm`. Called on close AND - after successful submit. -- `handleUseFormSubmit` — The `handleSubmit` function from `useForm`. - Used to wrap the submit handler with validation. -- `onFormSubmit` — Your submit callback. Receives validated form data. -- `formId` — Connects the internal `` to the modal's submit button. - -NERFormModal internally: - -1. Wraps `onFormSubmit` to call `reset()` after the submit callback -2. Renders a `` element with `noValidate` and `e.stopPropagation()` - -### useForm Setup - -Every form calls `useForm` with a Yup resolver and typed `defaultValues`: - -```tsx -import { useForm, Controller } from 'react-hook-form'; -import { yupResolver } from '@hookform/resolvers/yup'; -import * as yup from 'yup'; - -interface MyFormValues { - name: string; - description?: string; - amount: number; - isActive: boolean; -} - -const schema = yup.object().shape({ - name: yup.string().required('Name is required'), - description: yup.string().optional(), - amount: yup.number().required('Amount is required'), - isActive: yup.boolean().required() -}); - -const { - handleSubmit, - control, - reset, - formState: { errors } -} = useForm({ - resolver: yupResolver(schema), - defaultValues: { - name: defaultValues?.name ?? '', - description: defaultValues?.description ?? '', - amount: defaultValues?.amount ?? 0, - isActive: defaultValues?.isActive ?? false - } -}); -``` - -### Controller Pattern for MUI Components - -MUI components are not compatible with `register` because they don't -expose a native `ref`. Use `Controller` to bridge React Hook Form and -MUI: - -```tsx - ( - - )} -/> -{errors.name?.message} -``` - -For checkboxes: - -```tsx - ( - onChange(e.target.checked)} /> - )} -/> -``` - -For `Select`: - -```tsx - ( - - )} -/> -``` - -For `Autocomplete` (multi-select): - -```tsx - ( - opt.label} - isOptionEqualToValue={(opt, val) => opt.id === val.id} - value={memberOptions.filter((o) => value?.includes(o.id))} - onChange={(_, newVal) => onChange(newVal.map((v) => v.id))} - renderInput={(params) => } - /> - )} -/> -``` - -NOTE: For taking in a user as an input to a form, always prefer autocomplete over select, and in general only show members as options. - -## Step-by-Step: Creating a Modal Form - -### Step 1: Define the Form Values Interface and Schema - -Create the Yup schema and TypeScript interface for your form data. -The interface is used to type `useForm` and the `onSubmit` callback. - -```tsx -// In XFormModal.tsx -interface MyFormValues { - name: string; - code: number; - allowed: boolean; -} - -const schema = yup.object().shape({ - name: yup.string().required('Name is required'), - code: yup.number().typeError('Must be a number').required('Code is required'), - allowed: yup.boolean().required() -}); -``` - -### Step 2: Define the Form Modal Component Props - -The shared form modal accepts: `showModal`, `handleClose`, an optional -`defaultValues` for edit mode, and an `onSubmit` callback. - -```tsx -interface MyFormModalProps { - showModal: boolean; - handleClose: () => void; - defaultValues?: ExistingEntity; // from shared types - onSubmit: (data: MyFormValues) => void; -} -``` - -### Step 3: Set Up useForm with defaultValues - -Initialize `useForm` with `yupResolver` and compute `defaultValues` -from the optional prop. Use `??` to provide empty defaults for create -mode. - -```tsx -const MyFormModal = ({ - showModal, - handleClose, - defaultValues, - onSubmit -}: MyFormModalProps) => { - const toast = useToast(); - - const { - handleSubmit, - control, - reset, - formState: { errors } - } = useForm({ - resolver: yupResolver(schema), - defaultValues: { - name: defaultValues?.name ?? '', - code: defaultValues?.code ?? undefined, - allowed: defaultValues?.allowed ?? false - } - }); -``` - -### Step 4: Define the onFormSubmit Handler - -This wraps the parent's `onSubmit` with error handling. The parent -owns the mutation; this component just passes data up. - -```tsx -const onFormSubmit = async (data: MyFormValues) => { - try { - await onSubmit(data); - } catch (error: unknown) { - if (error instanceof Error) { - toast.error(error.message); - } - } - handleClose(); -}; -``` - -### Step 5: Render NERFormModal with Form Fields - -Pass `reset`, `handleSubmit`, and `onFormSubmit` to NERFormModal. -Use `Controller` to wrap each MUI field. Use `ReactHookTextField` -for simple text inputs. - -```tsx - return ( - reset({ - name: '', - code: undefined, - allowed: false - })} - handleUseFormSubmit={handleSubmit} - onFormSubmit={onFormSubmit} - formId={ - !!defaultValues - ? 'edit-thing-form' - : 'create-thing-form' - } - showCloseButton - > - - - - Name:* - - - - {errors.name?.message} - - - {/* More fields... */} - - - ); -}; -``` - -### Step 6: Create Thin Wrapper Components - -Create `CreateXModal` and `EditXModal` that own the mutation hook -and pass `mutateAsync` as `onSubmit`: - -**CreateXModal.tsx:** - -```tsx -const CreateThingModal = ({ showModal, handleClose }: CreateThingModalProps) => { - const { isLoading, isError, error, mutateAsync } = useCreateThing(); - - if (isError) return ; - if (isLoading) return ; - - return ; -}; -``` - -**EditXModal.tsx:** - -```tsx -const EditThingModal = ({ showModal, handleClose, thing }: EditThingModalProps) => { - const { isLoading, isError, error, mutateAsync } = useEditThing(thing.id); - - if (isError) return ; - if (isLoading) return ; - - return ; -}; -``` - -NOTE: while `CreateXModal.tsx` and `EditXModal.tsx` will typically be dealing with the same payload structure to pass to their mutation hooks, this is not always the case. To allow for differences between create and edit functionality, you can create a type with optional fields that contain all the data needed for both create and update mutations, and use that as the input parameter type for your onSubmit. In the form, you can determine if you are are editting or creating based on the detault values. For an example of these concepts look at the calendar event form. - -## Step-by-Step: Creating a Full-Page Form - -Full-page forms (like Work Package create/edit) skip NERFormModal and -render the `` element directly. The pattern is similar but uses -`PageLayout` instead of a modal. - -### Step 1: Create the Form View Component - -The form view accepts `defaultValues`, `onSubmit` (the mutation), -and a Yup `schema` from the parent: - -```tsx -const ThingFormView: React.FC = ({ exitActiveMode, onMutate, defaultValues, schema, breadcrumbs }) => { - const { - handleSubmit, - control, - formState: { errors } - } = useForm({ - resolver: yupResolver(schema), - defaultValues: { - name: defaultValues?.name ?? '' - // ... - } - }); - - const onSubmit = async (data: ThingFormPayload) => { - try { - await onMutate(data); - exitActiveMode(); - } catch (e) { - if (e instanceof Error) toast.error(e.message); - } - }; - - return ( - { - e.preventDefault(); - e.stopPropagation(); - handleSubmit(onSubmit)(e); - }} - noValidate - > - {/* Form fields using Controller */} - - ); -}; -``` - -### Step 2: Create the Wrapper Component - -The wrapper fetches data and owns the mutation: - -```tsx -const CreateThingForm: React.FC = () => { - const { mutateAsync } = useCreateThing(); - const history = useHistory(); - - const schema = yup.object().shape({ - name: yup.string().required('Name is required') - }); - - return ( - history.push(routes.THINGS)} - schema={schema} - breadcrumbs={[{ name: 'Things', route: routes.THINGS }]} - /> - ); -}; -``` - -## Shared Form Components - -### ReactHookTextField - -A pre-built `Controller`-wrapped `TextField`. Use for simple text, -number, and multiline inputs: - -```tsx -import ReactHookTextField from '../../components/ReactHookTextField'; - -; -``` - -### ReactHookEditableList - -For dynamic lists of items using `useFieldArray`. Items can be added -and removed: - -```tsx -import ReactHookEditableList from '../../components/ReactHookEditableList'; - -const { fields, append, remove } = useFieldArray({ - control, - name: 'bullets' -}); - -; -``` - -Each item in the field array MUST have a `detail` property: - -```tsx -append({ bulletId: -1, detail: '' }); -``` - -## Key Rules - -- `useForm` MUST always be called with `defaultValues`. NEVER - initialize a form without defaults — it causes uncontrolled-to- - controlled component warnings and broken reset behavior. - -- `useEffect` MUST NEVER be used to synchronize form state, reset - forms, or respond to prop changes in form components. React Hook - Form's `defaultValues` and `reset()` handle all of these cases. - -- The form component MUST NOT own the mutation hook. The parent - (CreateXModal / EditXModal) owns the mutation and passes - `mutateAsync` as the `onSubmit` prop. - -- The `reset` prop passed to `NERFormModal` MUST reset to empty/default - values (for create mode), NOT to `defaultValues`. NERFormModal calls - `reset()` both on close and after submit, so it needs to clear the - form for the next use. - -- Always use `e.stopPropagation()` in form submit handlers to prevent - event bubbling when forms are nested inside modals or other forms. - -- Use `noValidate` on all `

` elements to let Yup handle - validation instead of browser-native validation. - -- The `formId` prop on NERFormModal MUST match the `id` of the - internal `` element (NERFormModal handles this automatically). - -- Create/Edit mode is determined by the presence of `defaultValues`. - Use `!!defaultValues` to toggle titles and form IDs. - -- Yup schemas can be defined either at module level (for static - schemas) or inside the component (when the schema depends on props - or state). - -## Common Mistakes - -- **Using `useEffect` to sync form state with props.** This causes - stale data, infinite loops, and race conditions. Use - `defaultValues` in `useForm()` for initial values. If you need to - reset to new values after mount, call `reset(newValues)` directly - in a handler — never in a `useEffect`. - -- **Putting the mutation hook inside the form modal.** The form modal - should be reusable for create and edit. The mutation belongs in the - thin wrapper component (CreateXModal or EditXModal). - -- **Forgetting to pass `reset` to NERFormModal.** Without it, closing - and reopening the modal will show stale data from the previous - session. - -- **Passing `defaultValues` directly as the NERFormModal `reset` - prop.** The `reset` prop should reset to empty/blank values so the - form is clean when reused. Pass `() => reset({ name: '', ... })`. - -- **Using `register` with MUI components.** MUI components need - `Controller` because they don't expose native input refs. Only - use `register` with plain HTML inputs or inside - `ReactHookEditableList`. - -- **Forgetting `e.stopPropagation()` on form submit.** Without this, - submitting a form inside a modal can trigger parent form handlers, - leading to double submissions or unexpected behavior. - -## Reference Files - -These files demonstrate the prescribed patterns well: - -- `src/frontend/src/components/NERFormModal.tsx` — The core form - modal abstraction with reset-on-close and submit-then-reset -- `src/frontend/src/pages/AdminToolsPage/FinanceConfig/AccountCodeFormModal.tsx` - — Clean example of a shared create/edit form modal with Yup, - Controller, and ReactHookTextField -- `src/frontend/src/pages/AdminToolsPage/FinanceConfig/CreateAccountCodeModal.tsx` - — Clean create wrapper (mutation owner) -- `src/frontend/src/pages/AdminToolsPage/FinanceConfig/EditAccountCodeModal.tsx` - — Clean edit wrapper (passes `defaultValues`) -- `src/frontend/src/pages/FinancePage/FinanceComponents/VendorFormModal.tsx` - — Good example with multiple field types (text, checkbox, - autocomplete multi-select) -- `src/frontend/src/pages/WorkPackageForm/WorkPackageFormView.tsx` - — Full-page form pattern with `useFieldArray` -- `src/frontend/src/components/ReactHookTextField.tsx` — Shared - Controller-wrapped TextField component -- `src/frontend/src/components/ReactHookEditableList.tsx` — Shared - dynamic list component using `useFieldArray` - -## Checklist - -- [ ] Form uses `useForm` with `yupResolver` and typed `defaultValues` -- [ ] All MUI components are wrapped with `Controller` (not `register`) -- [ ] Yup schema validates all required fields with clear error messages -- [ ] `NERFormModal` receives `reset`, `handleUseFormSubmit`, and `onFormSubmit` -- [ ] `reset` prop resets to empty values, not to `defaultValues` -- [ ] Form component does NOT own the mutation hook -- [ ] Create wrapper passes `mutateAsync` as `onSubmit` (no `defaultValues`) -- [ ] Edit wrapper passes `mutateAsync` AND entity as `defaultValues` -- [ ] Create vs edit title/formId uses `!!defaultValues` check -- [ ] `showCloseButton` is set on the NERFormModal -- [ ] No `useEffect` is used for form state synchronization -- [ ] Form submit handler uses `e.stopPropagation()` -- [ ] `` element has `noValidate` attribute -- [ ] Error messages display via `` diff --git a/.claude/skills/general-practices/frontend-hooks-and-apis/SKILL.md b/.claude/skills/general-practices/frontend-hooks-and-apis/SKILL.md deleted file mode 100644 index f67fb42a4d..0000000000 --- a/.claude/skills/general-practices/frontend-hooks-and-apis/SKILL.md +++ /dev/null @@ -1,469 +0,0 @@ ---- -name: frontend-hooks-and-apis -description: Guide for creating React Query hooks and Axios API client functions in FinishLine. Covers query hooks, mutation hooks, API functions, query keys, cache invalidation, toast notifications, and frontend transformers. Use when creating new hooks, adding API calls, writing query or mutation hooks, working with React Query, implementing cache invalidation, or when asked how frontend data fetching works. ---- - -# Frontend Hooks and API Client Functions - -> **Summary:** All server state in FinishLine flows through React Query hooks backed by Axios API functions. Query hooks fetch data, mutation hooks write data, and both follow strict patterns for cache invalidation and toast notifications. - -## Overview - -FinishLine uses React Query v3 for all server state management. Every API interaction follows a two-layer pattern: a **hook** (in `src/frontend/src/hooks/`) wraps a React Query `useQuery` or `useMutation` call, which delegates the actual HTTP request to an **API function** (in `src/frontend/src/apis/`). This separation keeps hooks focused on caching/state concerns and API functions focused on HTTP concerns. - -The data flow for a **query** (read): - -``` -Component → useQuery hook → API function → Axios GET → Backend - ↓ -Component ← hook returns { data, isLoading } ← Axios response (transformed) -``` - -The data flow for a **mutation** (write): - -``` -Component → calls mutateAsync → useMutation hook → API function → Axios POST → Backend - ↓ -Component ← promise resolves ← hook invalidates cache + shows toast -``` - -A custom Axios instance (`src/frontend/src/utils/axios.ts`) automatically attaches the `organizationId` header on every request and converts backend error responses into JavaScript `Error` objects with meaningful messages. - -## Architecture - -``` -┌──────────────┐ ┌──────────────┐ -│ Component │ │ useToast() │ -│ (page/modal)│ │ (context) │ -└──────┬───────┘ └──────▲───────┘ - │ calls hook │ toast.success / error - ▼ │ -┌──────────────────────────────────┐ -│ Hook (useQuery / useMutation) │ -│ - query key management │ -│ - cache invalidation │ -│ - toast on success/error │ -│ - extracts .data from response │ -└──────────────┬───────────────────┘ - │ calls API fn - ▼ -┌──────────────────────────────────┐ -│ API Function (Axios call) │ -│ - builds URL via apiUrls │ -│ - sets transformResponse │ -│ - returns AxiosResponse │ -└──────────────┬───────────────────┘ - │ HTTP request - ▼ -┌──────────────────────────────────┐ -│ Backend (Express endpoint) │ -└──────────────────────────────────┘ -``` - -## File Locations - -- **Hooks:** `src/frontend/src/hooks/{feature}.hooks.ts` -- **API functions:** `src/frontend/src/apis/{feature}.api.ts` -- **Frontend transformers:** `src/frontend/src/apis/transformers/{feature}.transformer.ts` -- **URL builder:** `src/frontend/src/utils/urls.ts` (the `apiUrls` object) -- **Axios instance:** `src/frontend/src/utils/axios.ts` -- **Shared types:** `src/shared/src/types/{feature}-types.ts` -- **Toast hook:** `src/frontend/src/hooks/toasts.hooks.ts` - -Naming conventions: hook files and API files MUST use the same feature name prefix. If the hooks file is `calendar.hooks.ts`, the API file is `calendar.api.ts`. - -## Query Keys - -Query keys are the backbone of React Query's caching and invalidation system. Every query MUST have a key that uniquely identifies the data it fetches, and mutation hooks MUST invalidate the correct keys so the UI stays in sync. - -### Key Structure - -Query keys are arrays. The first element identifies the entity type, and subsequent elements narrow the scope: - -```typescript -// List query — base key -useQuery(['events'], ...) - -// Detail query — appends ID -useQuery(['events', id], ...) - -// Filtered query — appends filter params -useQuery( - ['filter-events', filterArgs], - ... -) - -// Scoped detail — appends multiple segments -useQuery( - ['events', id, 'with-members'], - ... -) -``` - -For keys that are reused across multiple hooks or need to be imported by other files for cross-feature invalidation, declare them as named constants at the top of the hooks file: - -```typescript -export const EVENT_KEY = ['events'] as const; -export const EVENT_TYPE_KEY = ['event-types'] as const; -``` - -This is optional — inline arrays like `['events']` are equally valid. The important thing is that keys are **consistent** so that invalidation works correctly. - -### Key Rules - -- Detail keys MUST include the entity ID as the second element -- Filter/variant keys MUST include the filter params or variant name -- Keys MUST use lowercase hyphen-separated strings (e.g., `'filter-events'`, `'event-types'`) -- NEVER use the same key for two different queries -- If a key is used for invalidation in another hook file, export it as a named constant - -## Step-by-Step: Adding a New Query Hook - -### Step 1: Add the URL to `apiUrls` - -In `src/frontend/src/utils/urls.ts`, add a URL builder function and export it: - -```typescript -// Near other calendar endpoints -const calendarShops = () => `${calendar()}/shops`; - -// In the apiUrls export object -export const apiUrls = { - // ...existing urls - calendarShops -}; -``` - -### Step 2: Write the API Function - -In `src/frontend/src/apis/{feature}.api.ts`: - -```typescript -import axios from '../utils/axios'; -import { apiUrls } from '../utils/urls'; -import { Shop } from 'shared'; - -export const getAllShops = () => { - return axios.get(apiUrls.calendarShops(), { - transformResponse: (data) => JSON.parse(data) as Shop[] - }); -}; -``` - -Key rules for API functions: - -- ALWAYS return the `AxiosResponse` directly (i.e., `return axios.get(...)` — do NOT extract `.data` inside the API function) -- Use `transformResponse` to parse JSON and apply frontend transformers when the response contains dates or nested objects that need transformation -- Import types from `shared`, not from local definitions -- Function names MUST match the HTTP semantics: `get*` for GET, `post*` / `create*` / `edit*` / `delete*` for POST/PUT/DELETE - -### Step 3: Write the Frontend Transformer (if needed) - -If the response contains `Date` fields (which arrive as strings from JSON) or nested objects that need transformation, create a transformer in `src/frontend/src/apis/transformers/{feature}.transformer.ts`: - -```typescript -import { Event } from 'shared'; - -export const eventTransformer = (event: Event): Event => { - if (!event || !event.scheduledTimes) return event; - return { - ...event, - dateCreated: new Date(event.dateCreated), - scheduledTimes: event.scheduledTimes.map((slot) => ({ - ...slot, - startTime: new Date(slot.startTime), - endTime: new Date(slot.endTime) - })) - }; -}; -``` - -Then use it in the API function's `transformResponse`: - -```typescript -import { eventTransformer } from './transformers/calendar.transformer'; - -export const getAllEvents = () => { - return axios.get(apiUrls.calendarEvents(), { - transformResponse: (data) => JSON.parse(data).map(eventTransformer) - }); -}; -``` - -See the [query-args-and-transformers skill](../../general-practices/query-args-and-transformers/SKILL.md) for detailed transformer patterns. - -### Step 4: Write the Query Hook - -In `src/frontend/src/hooks/{feature}.hooks.ts`: - -```typescript -import { useQuery } from 'react-query'; -import { Shop } from 'shared'; -import { getAllShops } from '../apis/calendar.api'; - -export const useAllShops = () => - useQuery(['shops'], async () => { - const { data } = await getAllShops(); - return data; - }); -``` - -For detail queries that take an ID parameter, use the `enabled` option to prevent fetching when the ID is undefined: - -```typescript -export const useSingleEvent = (id?: string) => { - return useQuery( - ['events', id], - async () => { - const { data } = await getSingleEvent(id!); - return data; - }, - { enabled: !!id } - ); -}; -``` - -### Query Hook Rules - -- The query function MUST destructure `{ data }` from the API response and return `data` -- Type the hook as `useQuery` -- Use `enabled` to conditionally skip queries when required params are missing -- Use `keepPreviousData: true` for filter/pagination queries to avoid UI flicker - -## Step-by-Step: Adding a New Mutation Hook - -### Step 1: Add the URL and API Function - -Same as query steps 1-2, but using `axios.post` (or `.put`, `.delete`): - -```typescript -export const postCreateShop = (payload: { name: string; description: string }) => { - return axios.post(apiUrls.calendarCreateShop(), payload, { - transformResponse: (data) => JSON.parse(data) as Shop - }); -}; -``` - -### Step 2: Write the Mutation Hook - -Every mutation hook MUST: - -1. Get the query client for cache invalidation -2. Return `useMutation` with explicit type parameters -3. Invalidate all relevant query keys on success -4. Show a toast on both success and error - -```typescript -import { useMutation, useQueryClient } from 'react-query'; -import { Shop } from 'shared'; -import { postCreateShop } from '../apis/calendar.api'; -import { useToast } from './toasts.hooks'; - -export const useCreateShop = () => { - const queryClient = useQueryClient(); - const toast = useToast(); - return useMutation( - async (payload) => { - const { data } = await postCreateShop(payload); - return data; - }, - { - onSuccess: () => { - queryClient.invalidateQueries(['shops']); - toast.success('Shop created successfully!'); - }, - onError: (error) => { - toast.error(error.message, 5000); - } - } - ); -}; -``` - -### Step 3: Use the Hook in a Component - -Components call mutation hooks and use `mutateAsync` for async/await control: - -```typescript -const CreateShopModal: React.FC = ({ open, onClose }) => { - const { mutateAsync: createShop } = useCreateShop(); - - const handleSubmit = async (payload: ShopFormData) => { - try { - await createShop(payload); - onClose(); - } catch (e) { - // Error toast is handled by the hook's onError. - // Re-throw only if the component needs to react - // further (e.g., keep modal open). - } - }; - - return ; -}; -``` - -### Mutation Keys - -Unlike query hooks, mutation hooks do NOT require an explicit mutation key. You can optionally add one as the first argument to `useMutation` if you need to reference the mutation elsewhere (e.g., for `useMutationState` or devtools tracking): - -```typescript -// Without mutation key (standard) -useMutation( - async (payload) => { ... }, - { onSuccess: () => { ... } } -); - -// With optional mutation key -useMutation( - ['shops', 'create'], - async (payload) => { ... }, - { onSuccess: () => { ... } } -); -``` - -### Mutation Type Parameters - -`useMutation` takes three type parameters: ``: - -- `TData` — the type returned by the mutation function (what the backend sends back) -- `TError` — always `Error` -- `TVariables` — the type of the argument passed to `mutateAsync(arg)` - -```typescript -useMutation(...); -// ^TData ^TError ^TVariables -``` - -### Cache Invalidation Rules - -Invalidation MUST cover all queries that could be affected by the mutation: - -- **Create** → invalidate the list key (`['shops']`) and any filtered variants (`['filter-shops']`) -- **Edit** → invalidate both the list key AND the specific detail key (`['shops', id]`) -- **Delete** → invalidate the list key and any filtered variants - -For cross-feature invalidation, import keys from other hook files: - -```typescript -import { EVENT_KEY } from './calendar.hooks'; - -export const useDeleteProject = () => { - const queryClient = useQueryClient(); - const toast = useToast(); - return useMutation<{ message: string }, Error, string>( - async (projectId) => { - const { data } = await deleteProject(projectId); - return data; - }, - { - onSuccess: () => { - queryClient.invalidateQueries(['projects']); - queryClient.invalidateQueries(EVENT_KEY); - toast.success('Project deleted successfully!'); - }, - onError: (error) => { - toast.error(error.message, 5000); - } - } - ); -}; -``` - -### Mutations Without Cache Invalidation - -Some mutations don't affect cached data (e.g., file uploads, Slack notifications). These still MUST show toasts but can skip invalidation: - -```typescript -export const useSlackUpcomingDeadlines = () => { - const toast = useToast(); - return useMutation<{ message: string }, Error, Date>( - async (deadline) => { - const { data } = await slackUpcomingDeadlines(deadline); - return data; - }, - { - onSuccess: () => { - toast.success('Deadlines sent to Slack!'); - }, - onError: (error) => { - toast.error(error.message, 5000); - } - } - ); -}; -``` - -## Toast Notifications - -The `useToast` hook (from `src/frontend/src/hooks/toasts.hooks.ts`) provides four methods: - -```typescript -const toast = useToast(); -toast.success('Created successfully!'); -toast.error('Something went wrong', 5000); -toast.info('Processing...'); -toast.warning('This action is irreversible'); -``` - -The second argument is an optional `autoHideDuration` in milliseconds. Error toasts SHOULD use `5000` to give users time to read the error. Success toasts use the default duration (no second argument). - -### Toast Message Conventions - -- **Success**: Past-tense action description — `'Shop created successfully!'`, `'Event updated successfully!'` -- **Error**: Use `error.message` from the caught error, which contains the backend's error message. Fall back to a generic message: `'Failed to create shop'` - -## Key Rules - -- Every query MUST have a key that uniquely identifies its data; use named constants for keys shared across files -- API functions MUST return `AxiosResponse` — NEVER extract `.data` inside the API function -- Query hooks MUST destructure `{ data }` from the API response -- Every mutation hook MUST call `useToast()` and show toasts in `onSuccess` and `onError` -- Every mutation hook MUST invalidate all relevant query keys on success -- Mutation hooks MUST return the `useMutation` result directly (the component uses `mutateAsync`) -- Types for API responses MUST come from the `shared` package -- Payload/input types that are unique to the frontend (e.g., form-specific types) MAY be defined in the hooks or API file - -## Common Mistakes - -- **Extracting `.data` inside the API function** — This breaks the pattern and makes the return type ambiguous. API functions MUST return `AxiosResponse`. The hook extracts `.data`. -- **Forgetting `transformResponse` for date fields** — JSON serialization turns `Date` objects into strings. Any response with date fields MUST use a transformer in `transformResponse`. -- **Using a plain string as a query key** — `useQuery('events', ...)` is fragile and doesn't support partial invalidation. Always use an array: `useQuery(['events'], ...)` or `useQuery(['events', id], ...)`. -- **Not invalidating filtered/variant queries** — If you have both `['events']` and a filter query (`['filter-events', args]`), a mutation that changes events MUST invalidate both. -- **Handling toasts in the component instead of the hook** — New code MUST handle toasts in the hook's `onSuccess`/`onError`. Components should NOT call `toast.success/error` for standard mutation outcomes. -- **Adding unnecessary mutation keys** — Mutation keys are optional and only needed if you have a specific use case for them. Don't add them by default. - -## Reference Files - -These files demonstrate the patterns well: - -- `src/frontend/src/hooks/calendar.hooks.ts` — Comprehensive example with query hooks, mutation hooks, query key exports, and cross-feature invalidation -- `src/frontend/src/apis/calendar.api.ts` — API functions with `transformResponse` and transformer usage -- `src/frontend/src/hooks/work-packages.hooks.ts` — Query hooks with parameter-based keys and mutation hooks -- `src/frontend/src/apis/work-packages.api.ts` — API functions using `workPackageTransformer` in `transformResponse` -- `src/frontend/src/apis/transformers/calendar.transformer.ts` — Frontend transformers for date conversion and nested object handling -- `src/frontend/src/hooks/toasts.hooks.ts` — The toast hook API -- `src/frontend/src/pages/CalendarPage/Components/CreateEventModal.tsx` — Example of consuming a mutation hook in a component - -## Checklist - -- [ ] Query keys are arrays that uniquely identify the data being fetched -- [ ] API function returns `AxiosResponse` (not extracted `.data`) -- [ ] Hook destructures `{ data }` from the API response -- [ ] `transformResponse` is set with appropriate transformer for responses containing dates -- [ ] Query hooks use `enabled` when parameters may be undefined -- [ ] Mutation hooks call `useToast()` and show toasts in `onSuccess` and `onError` -- [ ] Mutation hooks invalidate all affected query keys (list, detail, filtered variants) -- [ ] Response types are imported from `shared` -- [ ] URL is added to `apiUrls` in `src/frontend/src/utils/urls.ts` -- [ ] Hook and API files share the same feature-name prefix - -## Migration Notes - -> This section describes how this pattern differs from older code in the codebase. New code MUST follow the patterns above. When modifying existing files, update them to match these patterns where practical. - -**Toast notifications:** Many existing mutation hooks (e.g., `useCreateShop`, `useEditCalendar` in `calendar.hooks.ts`) do not include toast notifications. Instead, toasts were handled at the component level. The prescribed pattern moves toasts into the hook's `onSuccess`/`onError` callbacks so that every consumer of the hook gets consistent feedback without duplicating toast logic. When adding new mutations, always include toasts in the hook. When modifying existing mutation hooks, add `useToast()` and the `onSuccess`/`onError` toast callbacks. - -**API function return values:** Some existing API functions (e.g., `postCreateMachinery`, `postEditMachinery` in `calendar.api.ts`) extract `.data` from the Axios response and return the raw data instead of the `AxiosResponse`. The prescribed pattern is for API functions to always return `AxiosResponse`. When touching existing API functions that extract `.data`, refactor them to return the full response and update the corresponding hook to extract `.data`. - -**Mutation keys:** Some existing mutation hooks include an explicit mutation key as the first argument to `useMutation`. This is optional — new code does not need mutation keys unless there is a specific reason (e.g., tracking mutation state externally). Either approach is fine. diff --git a/.claude/skills/general-practices/postman-api-testing/SKILL.md b/.claude/skills/general-practices/postman-api-testing/SKILL.md deleted file mode 100644 index 6e6bf950d3..0000000000 --- a/.claude/skills/general-practices/postman-api-testing/SKILL.md +++ /dev/null @@ -1,320 +0,0 @@ ---- -name: postman-api-testing -description: Guide for using Postman to test and interact with the FinishLine API during development. Use when testing API endpoints, debugging backend issues, verifying request/response formats, or when asked how to use Postman with the local development environment. ---- - -# Postman API Testing - -> **Summary:** Postman enables developers to test API endpoints locally during development. This guide covers setup, authentication, common workflows, and troubleshooting for the FinishLine API running on localhost:3001. - -## Overview - -Postman is an API development tool that allows you to make HTTP requests to the FinishLine backend without needing the frontend interface. This is particularly useful for: - -- Testing new endpoints during development -- Debugging backend issues in isolation -- Verifying request and response formats -- Exploring available API data without UI constraints - -All API requests in local development target `http://localhost:3001`, which is the Express server running on your machine. Many endpoints require authentication using a user ID obtained from the `/users` endpoint. - -## Prerequisites - -Before you begin, ensure you have: - -- [Postman](https://www.postman.com/downloads/) installed -- The FinishLine backend running locally -- The PostgreSQL database running in Docker with seeded data - -## Verifying the API is Running - -Before making requests, confirm the backend is accessible: - -1. Start the backend server if not already running: - - ```bash - yarn backend:dev - ``` - -2. The console should show the server listening on port 3001 - -3. Make a test request to the base URL in Postman: `GET http://localhost:3001` - -If you receive a "Welcome to NER" message, your backend is running and listening on port 3001. This is also the default message you will see if the router cannot resolve the url you requested, so if you get this while trying to test an endpoint it is likely that you have a typo in the url or are using the wrong HTTP method (e.g. POST instead of GET). - -## Base URL - -All API requests in local development should be made to: - -``` -http://localhost:3001 -``` - -This is the Express server listening for HTTP requests. The backend handles routing, authentication, and business logic before querying the PostgreSQL database. - -## Authentication - -Many endpoints in the FinishLine API require authentication to enforce permission checks and organization scoping. Here's how to authenticate your Postman requests: - -### Step 1: Get a User ID - -First, fetch a user from the `/users` endpoint: - -1. Create a new GET request in Postman -2. Enter URL: `http://localhost:3001/users` -3. Click **Send** -4. The response contains an array of users with their `userId` fields -5. Copy a `userId` from any user in the response (typically a string like `"abc-123-def"`) - -### Step 2: Add Authorization Header - -For endpoints requiring authentication: - -1. Navigate to the **Headers** tab in your request -2. Add a new header with: - - **Key:** `authorization` - - **Value:** `` -3. Send your request - -Without proper authorization, protected endpoints will return `401 Unauthorized` or `403 Forbidden` responses depending on the permission level required. - -## Common Workflows - -### Fetching All Users - -**Endpoint:** `GET http://localhost:3001/users` - -**Purpose:** Retrieve all users in the system. Use this to find user IDs for authentication in other requests. - -**Authentication:** Not required - -**Steps:** - -1. Create a new request in Postman -2. Set method to **GET** using the dropdown menu -3. Enter URL: `http://localhost:3001/users` -4. Click **Send** - -**Response:** Array of user objects with `userId`, `firstName`, `lastName`, `email`, and role information. - -### Fetching All Projects - -**Endpoint:** `GET http://localhost:3001/project` - -**Purpose:** Retrieve all projects in the system. Useful for finding existing project data, WBS numbers, or materials associated with projects. - -**Authentication:** Check the route definition to confirm if required - -**Steps:** - -1. Create a new request -2. Set method to **GET** -3. Enter URL: `http://localhost:3001/project` -4. Add authorization header if needed (see Authentication section) -5. Click **Send** - -**Response:** Array of project objects with details like `projectId`, `name`, `wbsNum`, `status`, `teams`, and nested data. - -### Making Authenticated Requests - -For any endpoint that requires authentication: - -1. Fetch a user ID from `GET /users` (see above) -2. Add the `authorization` header with the user ID as the value -3. Make your request normally - -If you forget authorization on a protected route, the response will include an error message indicating permission denied or unauthorized access. - -### Creating or Updating Data (POST Requests) - -When testing endpoints that create or modify data: - -1. Set request method to **POST** -2. Add authentication header with a valid user ID -3. Navigate to the **Body** tab -4. Select **raw** and **JSON** format from the dropdown -5. Enter the request payload as valid JSON -6. Click **Send** - -Example JSON body structure (varies by endpoint): - -```json -{ - "name": "New Project", - "description": "Project description", - "leadId": "user-id-here" -} -``` - -Refer to the backend route validation rules in `src/backend/src/routes/` to determine required fields and formats. - -## Using Postman Features - -### Request Type Selection - -The dropdown menu to the left of the URL field allows you to select the HTTP request method. FinishLine follows this convention: - -- **GET** — Retrieve data (read operations) -- **POST** — Create new data, update existing data, or delete data - -Note: FinishLine does not use `PUT`, `PATCH`, or `DELETE` HTTP methods. All mutations use `POST`. - -### Key Tabs in Postman - -Postman provides several tabs for configuring requests: - -- **Params** — Add query parameters to your URL (e.g., `?limit=10&offset=0`) -- **Authorization** — Alternative way to set auth (use Headers tab for FinishLine) -- **Headers** — Add HTTP headers like `authorization`, `Content-Type`, `organizationId` -- **Body** — Include request payload for POST requests (select raw → JSON format) - -## Finding Endpoint URLs - -To discover available endpoints and their paths: - -1. **Check route files:** Backend routes are defined in `src/backend/src/routes/{feature}.routes.ts` -2. **Combine base paths:** The full URL is `index.ts` base path + route path - - Example: If `index.ts` has `app.use('/calendar', calendarRouter)` and the route defines `POST /shop/create`, the full endpoint is `POST /calendar/shop/create` -3. **Review validation:** Route files show which fields are required and their validation rules using `express-validator` - -## Organization Scoping - -FinishLine is a multi-tenant application. Most endpoints filter data by `organizationId`. In local development with seed data, the organization ID is typically included automatically via middleware. - -If an endpoint requires an explicit `organizationId` header: - -1. Go to the **Headers** tab -2. Add key: `organizationId` -3. Set value to a valid organization ID (check your seed data or database) - -## Troubleshooting - -### "Welcome to NER" Message - -**Problem:** You receive a plain text "Welcome to NER" response. - -**Cause:** The endpoint URL is incorrect or the route doesn't exist. This is the default response when Express can't find a matching route handler. - -**Solution:** - -- Double-check the endpoint URL for typos -- Verify the HTTP method matches the route definition (GET vs POST) -- Confirm the route is registered in `src/backend/index.ts` -- Check that the feature router is imported and mounted on the correct base path - -### Connection Refused or Network Error - -**Problem:** Postman cannot connect to `http://localhost:3001`. - -**Cause:** The backend server is not running. - -**Solution:** - -- Start the backend: `yarn backend:dev` or `yarn start` -- Verify the console shows "Server listening on port 3001" -- Check no other process is using port 3001 -- Wait a few seconds for the server to fully start after running the command - -### 401 Unauthorized or 403 Forbidden - -**Problem:** The endpoint returns a 401 or 403 error. - -**Cause:** Missing or invalid authentication, or insufficient permissions. - -**Solution:** - -- Ensure you've added the `authorization` header with a valid user ID -- Verify the user ID exists in the database (check `/users` response) -- Confirm the user has sufficient permissions for the operation (check the service method's permission check) -- Try using a different user with higher privileges (e.g., an admin user) - -### 400 Bad Request - -**Problem:** The endpoint returns a 400 error with validation messages. - -**Cause:** The request payload doesn't match the validation rules defined in the route. - -**Solution:** - -- Check the route file (`src/backend/src/routes/`) for validation rules -- Verify all required fields are present in the request body -- Ensure field types match expectations (string, number, date, boolean) -- Check for typos in field names -- Review the error response for specific validation failure details - -### Date Format Issues - -**Problem:** Date fields are rejected or cause errors. - -**Cause:** Invalid date string format. - -**Solution:** - -- Use ISO 8601 date format: `"2025-02-16T12:00:00.000Z"` -- Or use a simpler format: `"2025-02-16"` -- Avoid relative dates like "yesterday" or "last week" -- The backend controller parses date strings with `new Date()`, so any format recognized by JavaScript's Date constructor works - -### Empty or Unexpected Response - -**Problem:** The endpoint returns 200 OK but the data is empty or not what you expected. - -**Cause:** Data may be filtered by organization scope, soft-deleted, or the query returned no matches. - -**Solution:** - -- Check the database for relevant data: `yarn prisma:studio` -- Verify `dateDeleted` is `null` on the records you expect to see -- Confirm the records belong to the organization you're querying -- Review the service method's query filters and transformers - -## Available Endpoints Reference - -This table lists some core endpoints available in the FinishLine API. For a complete list, review the route files in `src/backend/src/routes/`. - -| Endpoint | Method | Description | Auth Required | -| ---------- | ------ | ----------------------------------------- | ------------- | -| `/users` | GET | Fetch all users with roles and settings | False | -| `/project` | GET | Fetch all projects with WBS and team data | True | - -_Note: This table is incomplete. When discovering new endpoints, add them here with their method, purpose, and authentication requirements._ - -## Key Rules - -- The base URL is always `http://localhost:3001` for local development -- Use **GET** for reads and **POST** for all mutations (create, update, delete) -- Authentication uses the `authorization` header with a user ID value -- Fetch user IDs from the `/users` endpoint before testing protected routes -- Full endpoint URLs combine the base path from `index.ts` and the route path -- Expect "Welcome to NER" for non-existent or incorrectly typed endpoints -- Validate request payloads against the route's `express-validator` rules -- Organization scoping is enforced — data is filtered by `organizationId` - -## Common Mistakes - -- **Not starting the backend server** before making requests -- **Forgetting the authorization header** on protected endpoints -- **Using incorrect HTTP methods** (e.g., PUT or DELETE instead of POST) -- **Mistyping the endpoint URL** (check the full path: base + route) -- **Not checking route validation rules** before constructing POST request bodies -- **Assuming all endpoints require authentication** — check the route definition -- **Ignoring 400 error details** — the response usually explains what's invalid - -## Reference Files - -- `src/backend/index.ts` — Route registration and middleware setup -- `src/backend/src/routes/{feature}.routes.ts` — Route definitions with HTTP methods and validation rules -- `src/backend/src/controllers/{feature}.controllers.ts` — Request handling logic -- `src/backend/src/services/{feature}.services.ts` — Business logic and permission checks - -## Tips for Efficient Testing - -- **Save requests in collections:** Organize related endpoints into Postman collections for easy reuse -- **Use environments:** Create a Postman environment with variables like `baseUrl` and `userId` to avoid repetitive typing -- **Inspect responses:** Check the response status, headers, and body to verify expected behavior -- **Test edge cases:** Try invalid inputs, missing fields, and unauthorized access to verify error handling -- **Review console logs:** The backend terminal shows request logs and error stack traces - -## Contributing to This Documentation - -If you discover additional endpoints, common workflows, or troubleshooting tips, please update this document following the same structure. Add new endpoints to the reference table, new workflows under Common Workflows, and new issues under Troubleshooting. diff --git a/.claude/skills/general-practices/prisma-schema-shared-types/SKILL.md b/.claude/skills/general-practices/prisma-schema-shared-types/SKILL.md deleted file mode 100644 index 0c2295eca8..0000000000 --- a/.claude/skills/general-practices/prisma-schema-shared-types/SKILL.md +++ /dev/null @@ -1,620 +0,0 @@ ---- -name: prisma-schema-shared-types -description: Guide for defining Prisma data models and keeping shared TypeScript types in sync in FinishLine. Covers schema conventions, enum patterns, multi-tenant organizationId scoping, the migration workflow, and the shared type barrel export. Use when adding new database models, creating or editing Prisma schema, defining shared types or interfaces, adding enums, running migrations, or when asked how the data layer works. ---- - -# Prisma Schema and Shared Types - -> **Summary:** How to define data models in Prisma and maintain corresponding TypeScript types in the shared package so backend and frontend stay in sync. - -## Overview - -FinishLine's data layer has two halves that must stay synchronized: the Prisma schema defines the database structure, and the shared TypeScript types define the API contract between backend and frontend. When you add or modify a model, you typically touch both. - -The Prisma schema lives at `src/backend/src/prisma/schema.prisma` — a single file containing all models, enums, and relations. The shared types live in `src/shared/src/types/` as feature-scoped TypeScript files that are re-exported through `src/shared/index.ts`. The backend uses Prisma-generated types internally but transforms them into shared types before sending responses. The frontend imports shared types directly and never references Prisma types. - -This separation exists because Prisma types mirror the database exactly (snake_case joins, nullable FKs, raw DateTime objects), while shared types represent the cleaned-up API contract (camelCase, resolved relations, computed fields). The transformer layer (covered in the `query-args-and-transformers` skill) bridges the gap. - -## Architecture - -``` -┌─────────────────────┐ -│ schema.prisma │ -│ (database truth) │ -└────────┬────────────┘ - │ prisma generate - ▼ -┌─────────────────────┐ -│ @prisma/client │ -│ (generated types) │ -└────────┬────────────┘ - │ used in services - ▼ -┌─────────────────────┐ -│ transformers │ -│ (Prisma → shared) │ -└────────┬────────────┘ - │ returns - ▼ -┌─────────────────────┐ -│ shared/src/types/ │ -│ (API contract) │ -└────────┬────────────┘ - │ imported by - ▼ -┌─────────────────────┐ -│ frontend │ -│ (React app) │ -└─────────────────────┘ -``` - -## File Locations - -- **Prisma schema:** `src/backend/src/prisma/schema.prisma` -- **Migrations:** `src/backend/src/prisma/migrations/` -- **Shared types:** `src/shared/src/types/{feature}-types.ts` -- **Barrel export:** `src/shared/index.ts` -- **Transformers:** `src/backend/src/transformers/{feature}.transformer.ts` -- **Query args:** `src/backend/src/prisma-query-args/{feature}.query-args.ts` - -## Prisma Schema Conventions - -### Model Naming - -Models use `PascalCase` with underscores separating logical words. This matches PostgreSQL conventions and keeps generated Prisma client types readable. - -```prisma -// CORRECT — PascalCase with underscores -model Reimbursement_Request { ... } -model Work_Package { ... } -model Change_Request { ... } -model Event_Type { ... } - -// WRONG — no underscores or camelCase -model ReimbursementRequest { ... } -model workPackage { ... } -``` - -### Field Naming - -Fields use `camelCase`. Foreign key fields end with `Id`. Relation fields use the related model name (camelCase). - -```prisma -model Event { - eventId String @id @default(uuid()) - title String - dateCreated DateTime @default(now()) - dateDeleted DateTime? - userCreatedId String - userCreated User @relation(...) - eventTypeId String - eventType Event_Type @relation(...) -} -``` - -### Primary Keys - -Every model MUST use a UUID string primary key with the pattern `@id @default(uuid())`. The ID field MUST be named `{camelCaseModelName}Id`. - -```prisma -model Vendor { - vendorId String @id @default(uuid()) - // ... -} - -model Reimbursement_Request { - reimbursementRequestId String @id @default(uuid()) - // ... -} -``` - -**Note:** Some older models use a bare `id` field (e.g., `Unit`, `Link_Type`, `Graph`). New models MUST use the `{modelName}Id` convention. - -### Timestamp Fields - -Every new model MUST include a `createdAt` field. An `updatedAt` field is optional and left to the developer's discretion based on whether tracking modification time is useful for the feature: - -```prisma -model My_New_Model { - myNewModelId String @id @default(uuid()) - // ... domain fields ... - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt // optional -} -``` - -**Note:** Most existing models use `dateCreated DateTime @default(now())`. A few newer models (`Part`, `Part_Submission`, `Part_Review`) use `createdAt`/`updatedAt`. New models MUST use `createdAt` (not `dateCreated`) for consistency with the newer convention. - -### Soft Deletion - -Models that support deletion use a nullable `dateDeleted` field and a relation to the deleting user, rather than actually removing rows: - -```prisma -model Example { - exampleId String @id @default(uuid()) - dateDeleted DateTime? - userDeletedId String? - userDeleted User? @relation( - name: "exampleDeleter", - fields: [userDeletedId], - references: [userId] - ) - // ... -} -``` - -Services MUST filter out soft-deleted records by checking `dateDeleted === null` in queries unless specifically retrieving deleted records. - -### Multi-Tenant Organization Scoping - -Every top-level domain model MUST be scoped to an organization, either directly or through a required parent relation. This is FinishLine's multi-tenancy mechanism — all data belongs to exactly one organization. - -**Direct scoping** (most models): - -```prisma -model Vendor { - vendorId String @id @default(uuid()) - name String - // ... other fields ... - organizationId String - organization Organization @relation( - fields: [organizationId], - references: [organizationId] - ) - - @@index([organizationId]) -} -``` - -**Indirect scoping through parent** (child models): - -```prisma -// Project gets organizationId through WBS_Element -model Project { - projectId String @id @default(uuid()) - wbsElementId String @unique - wbsElement WBS_Element @relation( - fields: [wbsElementId], - references: [wbsElementId] - ) - // No organizationId needed — WBS_Element has it -} - -// Work_Package gets it through Project → WBS_Element -model Work_Package { - workPackageId String @id @default(uuid()) - projectId String - project Project @relation( - fields: [projectId], - references: [projectId] - ) -} -``` - -**Rule:** If a model has `organizationId`, it MUST also have `@@index([organizationId])`. - -### Enums - -Enums use `PascalCase` names with `SCREAMING_SNAKE_CASE` values. Enum names use underscores to separate logical words, matching model naming: - -```prisma -enum Event_Status { - UNCONFIRMED - CONFIRMED - SCHEDULED - DONE -} - -enum Reimbursement_Status_Type { - PENDING_LEADERSHIP_APPROVAL - LEADERSHIP_APPROVED - PENDING_FINANCE - PENDING_SABO_SUBMISSION - SABO_SUBMITTED - ADVISOR_APPROVED - REIMBURSED - DENIED -} -``` - -Enums are placed at the top of `schema.prisma`, before model definitions. - -### Relations - -Name all relations explicitly when a model has multiple relations to the same target. Use descriptive `@relation(name: "...")` strings: - -```prisma -model User { - createdEvents Event[] @relation(name: "eventCreator") - deletedEvents Event[] @relation(name: "eventDeleter") -} - -model Event { - userCreatedId String - userCreated User @relation( - name: "eventCreator", - fields: [userCreatedId], - references: [userId] - ) - userDeletedId String? - userDeleted User? @relation( - name: "eventDeleter", - fields: [userDeletedId], - references: [userId] - ) -} -``` - -### Indexes - -Add `@@index` for any foreign key field that will be queried or filtered frequently. At minimum, always index `organizationId` and parent FK fields: - -```prisma -model Receipt { - // ... - reimbursementRequestId String - reimbursementRequest Reimbursement_Request @relation(...) - - @@index([reimbursementRequestId]) -} -``` - -### Unique Constraints - -Use `@@unique` with a `name` parameter for compound unique constraints. Organization-scoped uniqueness is a common pattern: - -```prisma -model Vendor { - // name must be unique within an organization - @@unique([name, organizationId], name: "uniqueVendor") -} - -model Change_Request { - // identifier is unique within an organization - @@unique([identifier, organizationId], - name: "uniqueChangeRequest") -} -``` - -## Shared Type Conventions - -### File Organization - -Each feature domain has its own type file in `src/shared/src/types/`: - -``` -src/shared/src/types/ -├── project-types.ts -├── calendar-types.ts -├── change-request-types.ts -├── reimbursement-requests-types.ts -├── team-types.ts -├── user-types.ts -├── finance-types.ts -├── work-package-types.ts -├── task-types.ts -├── bom-types.ts -├── part-review.types.ts -└── ... -``` - -Every type file MUST be re-exported from the barrel file at `src/shared/index.ts`: - -```typescript -export * from './src/types/calendar-types.js'; -export * from './src/types/project-types.js'; -// ... etc -``` - -**When adding a new type file**, add the corresponding `export *` line to `src/shared/index.ts`. Use the `.js` extension in the import path (ESM convention). - -### Type Naming - -Shared types use `PascalCase` with no underscores — they follow standard TypeScript conventions, not Prisma's: - -| Prisma Model | Shared Type | -| ----------------------- | ---------------------- | -| `Reimbursement_Request` | `ReimbursementRequest` | -| `Work_Package` | `WorkPackage` | -| `Event_Type` | `EventType` | -| `Change_Request` | `ChangeRequest` | - -### Entity Types vs Preview Types - -Many entities have both a full type and a lighter preview type. The full type includes resolved relations; the preview includes only essential fields for list views: - -```typescript -// Full type — used on detail pages -export interface Project extends WbsElement { - summary: string; - budget: number; - workPackages: WorkPackage[]; - teams: TeamPreview[]; - tasks: Task[]; - favoritedBy: User[]; -} - -// Preview type — used in lists and dropdowns -export interface ProjectPreview extends WbsElementPreview { - startDate?: Date; - endDate?: Date; - budget: number; - duration: number; - workPackages: WorkPackagePreview[]; - teams: { teamName: string; teamId: string }[]; -} -``` - -### Enum Mirroring - -Prisma enums MUST have corresponding TypeScript enums in shared types. The TypeScript enum uses `PascalCase` keys mapping to the Prisma `SCREAMING_SNAKE_CASE` values: - -```typescript -// Mirrors prisma enum Event_Status -export enum EventStatus { - UNCONFIRMED = 'UNCONFIRMED', - CONFIRMED = 'CONFIRMED', - SCHEDULED = 'SCHEDULED', - DONE = 'DONE' -} - -// Mirrors prisma enum WBS_Element_Status -export enum WbsElementStatus { - Inactive = 'INACTIVE', - Active = 'ACTIVE', - Complete = 'COMPLETE' -} -``` - -Both patterns exist in the codebase — some use the raw string as the value (`UNCONFIRMED = 'UNCONFIRMED'`), others use readable keys (`Inactive = 'INACTIVE'`). Either is acceptable as long as the values match the Prisma enum exactly. - -### Payload Types for Create and Edit - -Every feature MUST define separate payload types for create and edit operations. These types represent the data the frontend sends to the backend, not the database model structure. - -**Naming convention:** `Create{Feature}Payload` and `Edit{Feature}Payload` (or `{Feature}CreateArgs` for consistency with existing patterns). - -```typescript -// What the frontend sends to create an event -export interface EventTypeCreateArgs { - name: string; - calendarIds: string[]; - requiredMembers: boolean; - optionalMembers: boolean; - teams: boolean; - // ... boolean flags for optional fields -} - -// What the frontend sends to create a reimbursement product -export interface ReimbursementProductCreateArgs { - id?: string; - name: string; - cost: number; - refundSources: CreateRefundSourceArgs[]; -} -``` - -Payload types differ from entity types in important ways: they use IDs instead of resolved objects for relations (e.g., `calendarIds: string[]` not `calendars: Calendar[]`), they omit server-generated fields (`dateCreated`, `organizationId`, `userCreated`), and they may include validation-specific structures. - -**When the codebase doesn't yet have separate create/edit payloads for a feature, add them.** Even if the current code passes raw objects or uses inline types, new and modified code MUST use explicit payload types in the shared package. - -### Type Relationships Across Files - -Shared type files import from each other. Keep imports minimal — prefer importing `Preview` types over full types when the full relation isn't needed: - -```typescript -// In project-types.ts -import { TeamPreview } from './team-types.js'; -import { User, UserPreview } from './user-types.js'; - -export interface Project extends WbsElement { - teams: TeamPreview[]; // NOT Team[] - lead?: User; -} -``` - -## Step-by-Step: Adding a New Model - -### 1. Define the Prisma Model - -Add the model to `src/backend/src/prisma/schema.prisma`: - -```prisma -model Schedule_Slot { - scheduleSlotId String @id @default(uuid()) - startTime DateTime - endTime DateTime - allDay Boolean @default(false) - eventId String - event Event @relation( - fields: [eventId], - references: [eventId] - ) - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - - @@index([startTime]) - @@index([endTime]) -} -``` - -### 2. Add Any New Enums - -Place enums at the top of the schema file, before models: - -```prisma -enum Conflict_Status { - PENDING - APPROVED - DENIED - NO_CONFLICT -} -``` - -### 3. Run the Migration - -```bash -yarn prisma:migrate -``` - -This runs `npx prisma migrate dev` from the backend directory. It will prompt you for a migration name — use a descriptive kebab-case name like `add-schedule-slots` or `add-conflict-status-enum`. The migration creates a new SQL file in `src/backend/src/prisma/migrations/`. - -After migrating, Prisma automatically runs `prisma generate` to update the client types. - -**If using Docker for development:** - -```bash -yarn docker:prisma:migrate -``` - -### Manual Migration Steps - -Prisma can auto-generate migrations for simple changes (adding a new model, adding a nullable column, adding an enum value). However, some schema changes require you to **manually edit the generated SQL migration file** because Prisma cannot safely resolve them on its own. Common scenarios: - -- **Adding a required (non-nullable) field to an existing table.** The migration will fail if the table already has rows, because existing rows have no value for the new column. You must either give the column a `@default(...)` in the schema, or manually edit the migration SQL to set a backfill value before adding the `NOT NULL` constraint: - - ```sql - -- Step 1: Add column as nullable - ALTER TABLE "My_Model" ADD COLUMN "newField" TEXT; - -- Step 2: Backfill existing rows - UPDATE "My_Model" SET "newField" = 'default_value'; - -- Step 3: Set NOT NULL constraint - ALTER TABLE "My_Model" - ALTER COLUMN "newField" SET NOT NULL; - ``` - -- **Renaming a column or table.** Prisma interprets renames as a drop + create, which destroys data. You must replace the generated SQL with `ALTER TABLE ... RENAME COLUMN`. - -- **Changing a column's type** (e.g., `Int` → `String`). Prisma may generate a destructive migration. You must manually write a `USING` cast or a multi-step migration. - -- **Splitting or merging models.** Any structural refactor that moves data between tables needs manual SQL to migrate the data. - -**Workflow for manual migrations:** - -1. Run `yarn prisma:migrate` — Prisma generates the migration file -2. **Before applying**, open the generated SQL file in `src/backend/src/prisma/migrations/{timestamp}_{name}/migration.sql` -3. Edit the SQL to handle the data migration safely -4. Run `yarn prisma:migrate` again to apply the edited migration - -Alternatively, use `npx prisma migrate dev --create-only` from `src/backend` to generate the migration file without applying it, edit it, then run `yarn prisma:migrate` to apply. - -### 4. Define the Shared Type - -Create or update the appropriate file in `src/shared/src/types/`: - -```typescript -// In calendar-types.ts - -export enum ConflictStatus { - PENDING = 'PENDING', - APPROVED = 'APPROVED', - DENIED = 'DENIED', - NO_CONFLICT = 'NO_CONFLICT' -} - -export interface ScheduleSlot { - scheduleSlotId: string; - startTime: Date; - endTime: Date; - allDay: boolean; -} - -export interface ScheduleSlotCreateArgs { - startTime: Date; - endTime: Date; - allDay: boolean; -} -``` - -### 5. Export from Barrel - -If you created a new type file, add it to `src/shared/index.ts`: - -```typescript -export * from './src/types/my-new-types.js'; -``` - -### 6. Build Shared Package - -After modifying shared types, rebuild the shared package so the backend and frontend can see the changes: - -```bash -yarn workspace shared build -``` - -Or if using the dev server, it may handle this automatically. - -### 7. Create Transformer and Query Args - -See the `query-args-and-transformers` skill for how to create the Prisma-to-shared-type transformer and the corresponding query args. - -## Key Rules - -- Every Prisma model MUST have a UUID primary key: `{modelName}Id String @id @default(uuid())` -- Every new model MUST include `createdAt DateTime @default(now())`; `updatedAt` is optional -- Every top-level model MUST have `organizationId` directly or inherit it through a required parent relation -- Every `organizationId` field MUST have a corresponding `@@index([organizationId])` -- Soft deletion uses `dateDeleted DateTime?` — NEVER use hard deletes -- Prisma enums MUST have mirrored TypeScript enums in `src/shared/src/types/` -- Shared types MUST be re-exported from `src/shared/index.ts` -- New features MUST define separate `Create` and `Edit` payload types in shared -- Payload types use IDs (`teamIds: string[]`) not resolved objects (`teams: Team[]`) -- Foreign key fields MUST be indexed with `@@index` - -## Common Mistakes - -- **Forgetting to re-export from `src/shared/index.ts`.** The frontend won't see your new types until they're re-exported from the barrel file. If imports fail with "not exported," check the barrel. - -- **Using `id` instead of `{modelName}Id` for the primary key.** Some older models use bare `id`, but new models MUST use the descriptive name. - -- **Missing `organizationId` on a top-level model.** If your model doesn't have a required parent that chains up to an organization, it needs `organizationId` directly. Without it, the service layer can't enforce multi-tenant isolation. - -- **Forgetting `@@index` on foreign keys.** Every FK field that appears in `WHERE` clauses needs an index. At minimum, always index `organizationId` and parent relation FKs. - -- **Prisma enum values not matching shared type values.** The Prisma enum value `PENDING_LEADERSHIP_APPROVAL` must match exactly as the string in the TypeScript enum. A mismatch causes runtime errors when transforming data. - -- **Not running `yarn prisma:migrate` after schema changes.** The database won't reflect your changes until you run the migration. The Prisma client types also won't update until `prisma generate` runs (which `migrate dev` does automatically). - -- **Editing already-applied migration files.** NEVER modify migration files that have already been applied to a database. You CAN and sometimes MUST edit a migration file before it is applied (see "Manual Migration Steps" above). Once applied, create a new migration instead. - -- **Adding a required field without a default or backfill.** If your new column is non-nullable and the table has existing rows, the migration will fail. See "Manual Migration Steps" for how to handle this. - -## Reference Files - -These files demonstrate the conventions well: - -- `src/backend/src/prisma/schema.prisma` — The single source of truth for all models and enums -- `src/shared/src/types/calendar-types.ts` — Good example of entity types, preview types, enums, and create args -- `src/shared/src/types/reimbursement-requests-types.ts` — Good example of complex nested types and multiple payload types -- `src/shared/src/types/project-types.ts` — Good example of type hierarchies (`WbsElement` → `Project`, preview types) -- `src/shared/index.ts` — Barrel export file; every new type file must be added here - -## Checklist - -- [ ] Model name uses `PascalCase` with underscores (e.g., `My_New_Model`) -- [ ] Primary key is `{modelName}Id String @id @default(uuid())` -- [ ] Model has `createdAt DateTime @default(now())` (and optionally `updatedAt DateTime @updatedAt`) -- [ ] Model has `organizationId` (directly or via parent chain) -- [ ] `organizationId` has `@@index([organizationId])` -- [ ] All FK fields have `@@index` declarations -- [ ] Named relations used when multiple relations target the same model -- [ ] Soft deletion uses `dateDeleted DateTime?` pattern (if applicable) -- [ ] Corresponding shared TypeScript types created in `src/shared/src/types/` -- [ ] Shared type file re-exported from `src/shared/index.ts` -- [ ] Prisma enums mirrored as TypeScript enums in shared types -- [ ] Separate `Create` and `Edit` payload types defined for API operations -- [ ] Payload types use IDs for relations, not resolved objects -- [ ] Migration created with `yarn prisma:migrate` -- [ ] Shared package rebuilt with `yarn workspace shared build` - -## Migration Notes - -> This section describes how this pattern differs from older code in the -> codebase. New code MUST follow the patterns above. When modifying existing -> files, update them to match these patterns where practical. - -**Timestamp fields:** Most existing models use `dateCreated DateTime @default(now())`. A few newer models (`Part`, `Part_Submission`, `Part_Review`, `Part_Review_Popup`) use `createdAt`/`updatedAt`. New models MUST use `createdAt` (not `dateCreated`) for the creation timestamp. - -**Primary key naming:** Some older models use a bare `id` field (e.g., `Unit`, `Link_Type`, `Material_Type`, `Manufacturer`, `Graph`, `Graph_Collection`). New models MUST use `{modelName}Id`. - -**Payload types:** The codebase is inconsistent about defining explicit create/edit payload types. Some features have them (e.g., `EventTypeCreateArgs`, `ReimbursementProductCreateArgs`, `ScheduleSlotCreateArgs`), while others pass inline objects or rely on partial Prisma types. The naming also varies between `CreateArgs`, `CreatePayload`, `ApiInputs`, and `FormInput`. New code MUST define explicit payload types. Prefer the `{Feature}CreateArgs` naming to match the majority of existing patterns. diff --git a/.claude/skills/general-practices/query-args-and-transformers/SKILL.md b/.claude/skills/general-practices/query-args-and-transformers/SKILL.md deleted file mode 100644 index 5a58a7f5f2..0000000000 --- a/.claude/skills/general-practices/query-args-and-transformers/SKILL.md +++ /dev/null @@ -1,493 +0,0 @@ ---- -name: query-args-and-transformers -description: Guide for Prisma query args and transformer functions in FinishLine. Query args define reusable select/include objects for Prisma queries. Transformers convert Prisma results into shared types for the API. Use when creating query args, writing transformers, fetching data from Prisma for API responses, or when asked how data flows from the database to the frontend. ---- - -# Query Args and Transformers - -> **Summary:** Query args define what data Prisma fetches from the database. Transformers convert that Prisma data into the shared types sent to the frontend. Together they form the data-shaping layer between Prisma and the API response. - -## Overview - -When a service method needs to return data to the frontend, it goes through two steps: - -1. **Query args** tell Prisma exactly which fields and relations to fetch. They are reusable `select`/`include` objects defined with `Prisma.validator`. -2. **Transformers** take the typed Prisma result and reshape it into a shared type (defined in `src/shared/`) that the frontend expects. - -This separation exists because Prisma's auto-generated types (column names, nested relation shapes, enum values) often differ from the API contract. Transformers handle renaming fields, mapping enums, flattening relations, and filtering out internal data. - -**Critical distinction:** Query args and transformers are ONLY for data being returned to the frontend. For internal queries in a service (validation checks, duplicate detection, permission lookups), use inline `select: {}` clauses directly in the Prisma call. See the "Internal Queries" section below. - -## Architecture - -``` - Service Method - │ - │ uses query args to fetch - ▼ -┌──────────────┐ -│ Prisma │ returns typed result: -│ Query Args │ Prisma.XGetPayload -└──────┬───────┘ - │ - │ passes result to transformer - ▼ -┌──────────────┐ -│ Transformer │ returns shared type -│ │ (API contract) -└──────┬───────┘ - │ - ▼ - Controller sends as JSON -``` - -## File Locations - -| Layer | Path | Naming | -| ------------ | ----------------------------------------------------------- | ---------------------- | -| Query args | `src/backend/src/prisma-query-args/{feature}.query-args.ts` | `get{Entity}QueryArgs` | -| Transformers | `src/backend/src/transformers/{feature}.transformer.ts` | `{entity}Transformer` | -| Shared types | `src/shared/src/types/{feature}-types.ts` | TypeScript interfaces | - -## Query Args - -### Structure - -Every query args file follows the same pattern: export a type alias using `ReturnType`, and export a function that returns a `Prisma.validator` call. - -```typescript -// src/backend/src/prisma-query-args/shop.query-args.ts -import { Prisma } from '@prisma/client'; -import { getUserQueryArgs } from './user.query-args.js'; - -export type ShopQueryArgs = ReturnType; - -export const getShopQueryArgs = (organizationId: string) => - Prisma.validator()({ - include: { - userCreated: getUserQueryArgs(organizationId) - } - }); -``` - -The type alias (`ShopQueryArgs`) is used by the transformer to type its input parameter via `Prisma.ShopGetPayload`. This creates end-to-end type safety: if you change what the query fetches, the transformer's input type updates automatically and TypeScript will flag any mismatches. - -### `select` vs `include` - -**Always prefer `select` over `include`.** `include` fetches all columns on the relation plus the specified nested relations. `select` fetches only the fields you list. - -```typescript -// GOOD — fetches only what's needed -teams: { - select: { - teamName: true, - teamId: true - } -} - -// AVOID — fetches every column on Team -teams: true - -// ALSO AVOID — include fetches all Team -// columns plus the nested relation -teams: { - include: { - teamType: true - } -} -``` - -Use `include` only when the transformer genuinely needs all (or nearly all) columns from the relation AND also needs nested relations. The `getWorkPackageQueryArgs` function uses `include` on `wbsElement` because the transformer needs most of its fields plus several nested relations. But even within that, nested relations like `teams` use `select` when only a few fields are needed. - -A good example of selective fetching is `getWorkPackagePreviewQueryArgs`, which uses `select` at every level to fetch the minimal data for a dropdown/list view: - -```typescript -export const getWorkPackagePreviewQueryArgs = () => - Prisma.validator()({ - select: { - blockedBy: true, - wbsElement: { - select: { - wbsElementId: true, - carNumber: true, - projectNumber: true, - workPackageNumber: true, - dateCreated: true, - dateDeleted: true, - name: true, - lead: getUserPreviewQueryArgs(), - manager: getUserPreviewQueryArgs(), - status: true - } - }, - project: { - select: { - projectId: true, - wbsElement: { - select: { - name: true, - links: getLinkQueryArgs() - } - } - } - }, - startDate: true, - duration: true, - workPackageId: true, - stage: true - } - }); -``` - -### Nesting - -Be very careful about nested query args. Every level of nesting adds database joins and increases query cost. Only include nested relations when the transformer actually needs that data to satisfy the shared type. - -**Good reasons to nest:** - -- The shared type has a `userCreated: User` field → nest `getUserQueryArgs` -- The shared type has a `teams: Team[]` field that needs team names → nest with `select: { teamName: true, teamId: true }` - -**Bad reasons to nest:** - -- "The frontend might need it eventually" — add it when it's actually needed -- Nesting three or more levels deep without confirming the transformer uses all that data - -When nesting gets deep, consider whether a separate endpoint with its own query args would be better. For example, `getEventQueryArgs` and `getEventWithMembersQueryArgs` exist as two separate functions because the member-expanded version adds significant nesting that most callers don't need. - -### `organizationId` Parameter - -Many query args accept `organizationId` to scope nested relations. The most common case is filtering user roles to the current organization: - -```typescript -export const getUserQueryArgs = (organizationId?: string) => - Prisma.validator()({ - select: { - roles: organizationId ? { where: { organizationId } } : true, - userId: true, - firstName: true, - lastName: true, - email: true - } - }); -``` - -Pass `organizationId` through from the service method. If your query args don't need to filter nested relations by org, the parameter can be omitted. - -### Filtering Soft-Deleted Records - -Query args MUST filter out soft-deleted records in nested relations using `where: { dateDeleted: null }`. This applies at every nesting level: - -```typescript -export const getWorkPackageQueryArgs = (organizationId: string) => - Prisma.validator()({ - include: { - blockedBy: { - where: { dateDeleted: null } - }, - events: { - where: { dateDeleted: null }, - ...getEventQueryArgs(organizationId) - }, - wbsElement: { - include: { - descriptionBullets: { - where: { dateDeleted: null }, - ...getDescriptionBulletQueryArgs(organizationId) - }, - changes: { - where: { - changeRequest: { dateDeleted: null } - } - }, - blocking: { - where: { - wbsElement: { dateDeleted: null } - } - } - } - } - } - }); -``` - -Note: the top-level `dateDeleted: null` filter is applied in the service's `where` clause, not in the query args. Query args handle nested relation filtering. - -### Circular Dependencies - -The `user.query-args.ts` file has a comment: `// DO NOT CALL ANY OTHER QUERY ARGS FROM HERE TO AVOID CIRCULAR DEPENDENCIES`. Because user query args are nested into almost every other query args file, they sit at the bottom of the dependency tree. If user query args imported from, say, `event.query-args.ts`, it would create a circular import. Keep this in mind when adding new nesting. - -## Transformers - -### Structure - -A transformer is a pure function that takes a Prisma result (typed using the query args) and returns a shared type. - -```typescript -// src/backend/src/transformers/calendar.transformer.ts -import { Prisma } from '@prisma/client'; -import { Shop } from 'shared'; -import { ShopQueryArgs } from '../prisma-query-args/shop.query-args.js'; -import { userTransformer } from './user.transformer.js'; - -export const shopTransformer = (shop: Prisma.ShopGetPayload): Shop => { - return { - shopId: shop.shopId, - name: shop.name, - description: shop.description, - dateCreated: shop.dateCreated, - userCreated: userTransformer(shop.userCreated) - }; -}; -``` - -**The input type** is always `Prisma.{Model}GetPayload<{QueryArgs}>`. This gives you a type that exactly matches what Prisma returns when using those query args. - -**The return type** is always the shared type from `src/shared/`. The transformer's job is to bridge any gap between the two. - -### Common Transformer Operations - -**Renaming fields** — when Prisma column names differ from the shared type: - -```typescript -color: calendar.colorHexCode, -``` - -**Mapping enums** — Prisma enums and shared enums are separate types. Create a mapping: - -```typescript -export const eventStatusTransformer = (status: PrismaEventStatus): EventStatus => { - const mapping: Record = { - UNCONFIRMED: EventStatus.UNCONFIRMED, - CONFIRMED: EventStatus.CONFIRMED, - SCHEDULED: EventStatus.SCHEDULED, - DONE: EventStatus.DONE - }; - return mapping[status]; -}; -``` - -**Converting nulls to undefined** — Prisma uses `null` for optional fields, but shared types often use `undefined`: - -```typescript -location: event.location ?? undefined, -zoomLink: event.zoomLink ?? undefined, -``` - -**Transforming nested relations** — call other transformers for nested objects: - -```typescript -requiredMembers: - event.requiredMembers.map(userTransformer), -teams: event.teams.map((team) => ({ - ...team, - members: team.members.map(userTransformer), - leads: team.leads.map(userTransformer), - head: userTransformer(team.head) -})), -``` - -**Computing derived fields** — some shared types have fields that don't exist in the database: - -```typescript -endDate: calculateEndDate( - wpInput.startDate, wpInput.duration -), -deleted: wpInput.wbsElement.dateDeleted !== null, -``` - -### Composing Transformers - -Transformers compose naturally. A `shopMachineryTransformer` calls `shopTransformer`, which calls `userTransformer`: - -```typescript -export const shopMachineryTransformer = (sm: Prisma.Shop_MachineryGetPayload): ShopMachinery => { - return { - shopMachineryId: sm.shopMachineryId, - shop: shopTransformer(sm.shop), - quantity: sm.quantity - }; -}; -``` - -This mirrors the nesting in query args: `getMachineryQueryArgs` includes `getShopMachineryQueryArgs`, which includes `getShopQueryArgs`. The transformer chain matches the query args chain. - -### Preview Transformers - -When the frontend needs a lightweight version of an entity (for dropdowns, lists, or cards), create a separate "preview" query args and transformer pair: - -```typescript -// Query args: minimal select -export const getWorkPackagePreviewQueryArgs = () => - Prisma.validator()({ - select: { - /* only essential fields */ - } - }); - -// Transformer: maps to preview type -export const workPackagePreviewTransformer = ( - wp: Prisma.Work_PackageGetPayload -): WorkPackagePreview => { - return { - /* minimal fields */ - }; -}; -``` - -This avoids fetching heavyweight data (nested changes, description bullets, events) when all the frontend needs is a name and ID. - -## Internal Queries (Not for API Response) - -When a service method queries the database for validation, permission checks, duplicate detection, or calculations — NOT to return data to the frontend — do NOT use query args. Write inline `select` clauses: - -```typescript -// Checking for duplicates: only need the ID -const duplicate = await prisma.shop.findFirst({ - where: { - organizationId: organization.organizationId, - dateDeleted: null, - name: { equals: name, mode: 'insensitive' } - }, - select: { shopId: true } -}); - -// Counting members: only need the count -const team = await prisma.team.findUnique({ - where: { teamId }, - select: { - _count: { select: { members: true } } - } -}); - -// Checking existence and org ownership -const calendar = await prisma.calendar.findUnique({ - where: { calendarId }, - select: { - calendarId: true, - organizationId: true, - dateDeleted: true - } -}); -``` - -The principle is simple: query args exist to satisfy shared types via transformers. Everything else should fetch the minimum data needed. - -## How It All Connects in a Service - -Here's the full flow in a service method: - -```typescript -static async getSingleShop( - shopId: string, - organization: Organization -): Promise { - // 1. Fetch with query args (for API response) - const shop = await prisma.shop.findUnique({ - where: { shopId }, - ...getShopQueryArgs(organization.organizationId) - }); - - // 2. Validate existence - if (!shop) throw new NotFoundException( - 'Shop', shopId - ); - if (shop.dateDeleted) - throw new DeletedException('Shop', shopId); - if ( - shop.organizationId !== - organization.organizationId - ) - throw new InvalidOrganizationException('Shop'); - - // 3. Transform and return - return shopTransformer(shop); -} -``` - -For mutations that need both internal lookups and a final return: - -```typescript -static async editShop( - submitter: User, - shopId: string, - name: string, - description: string, - organization: Organization -): Promise { - // Internal lookup — inline select - const existing = await prisma.shop.findUnique({ - where: { shopId }, - select: { - shopId: true, - organizationId: true, - dateDeleted: true - } - }); - - if (!existing) throw new NotFoundException( - 'Shop', shopId - ); - // ... more validation ... - - // Write + fetch for response — query args - const updated = await prisma.shop.update({ - where: { shopId }, - data: { name, description }, - ...getShopQueryArgs(organization.organizationId) - }); - - return shopTransformer(updated); -} -``` - -## Key Rules - -- Query args are ONLY for data returned to the frontend via transformers. Use inline `select` for internal queries. -- Always prefer `select` over `include` to avoid over-fetching. -- Only add nested query args when the transformer actually needs that data for the shared type. -- Export a type alias using `ReturnType` for every query args function. -- Transformer input MUST be typed as `Prisma.{Model}GetPayload<{QueryArgs}>`. -- Transformer return type MUST be a shared type from `src/shared/`. -- NEVER return raw Prisma objects from a service. Always transform. -- Filter `dateDeleted: null` in nested relations within query args. -- Convert Prisma `null` to `undefined` when the shared type uses optional fields. -- Map Prisma enums to shared enums explicitly — do not assume they are the same type. -- Do not import other query args from `user.query-args.ts` to avoid circular dependencies. - -## Common Mistakes - -- **Using query args for internal lookups.** Fetching full nested relations just to check if a record exists wastes database resources. Use `select: { id: true }`. -- **Using `include: true`** on a relation when only a few fields are needed. Switch to `select` with specific fields. -- **Adding deep nesting "just in case."** Every nested level adds joins. Only nest what the transformer uses. -- **Forgetting `dateDeleted: null`** in nested `where` clauses within query args. This returns soft-deleted child records. -- **Returning Prisma objects directly** without a transformer. Even if the shapes look identical today, they can diverge when the schema or shared types change. -- **Forgetting `?? undefined`** on nullable Prisma fields that map to optional shared type fields. TypeScript will catch this, but it's easy to miss. -- **Not creating a preview variant** when a lightweight version exists. If the frontend has both a detail view and a list view, make separate query args and transformers for each. - -## Reference Files - -- `src/backend/src/prisma-query-args/work-packages.query-args.ts` — Shows both a full query args (with `include`) and a preview query args (with `select` throughout) -- `src/backend/src/prisma-query-args/event.query-args.ts` — Two variants (`getEventQueryArgs` and `getEventWithMembersQueryArgs`) for different data needs -- `src/backend/src/prisma-query-args/user.query-args.ts` — Base-level query args with `select`-first approach, org-scoped role filtering, and circular dependency warning -- `src/backend/src/transformers/calendar.transformer.ts` — Comprehensive transformer file showing enum mapping, null-to-undefined conversion, nested transformers, and soft-delete filtering -- `src/backend/src/transformers/work-packages.transformer.ts` — Demonstrates computed fields (`endDate`, `deleted`) and full/preview transformer pair - -## Checklist - -When adding query args and a transformer for a new entity: - -- [ ] Query args function uses `Prisma.validator()` -- [ ] Type alias exported as `ReturnType` -- [ ] `organizationId` parameter included if nested relations need org scoping -- [ ] `select` preferred over `include` at every level -- [ ] Nested relations filtered with `where: { dateDeleted: null }` where applicable -- [ ] No unnecessary deep nesting -- [ ] No circular dependency on `user.query-args.ts` -- [ ] Transformer input typed as `Prisma.{Model}GetPayload<{QueryArgs}>` -- [ ] Transformer return type is the shared type from `src/shared/` -- [ ] All nullable Prisma fields converted with `?? undefined` if shared type uses optional -- [ ] Prisma enums mapped to shared enums explicitly -- [ ] Nested relations transformed using their respective transformer functions -- [ ] Soft-deleted nested records filtered if not handled in query args -- [ ] Preview variant created if a lightweight view is needed diff --git a/.claude/skills/general-practices/react-components/SKILL.md b/.claude/skills/general-practices/react-components/SKILL.md deleted file mode 100644 index 861a669e90..0000000000 --- a/.claude/skills/general-practices/react-components/SKILL.md +++ /dev/null @@ -1,546 +0,0 @@ ---- -name: react-components -description: Guide for building and organizing React components in FinishLine. Covers shared vs page-specific component decisions, prop interface design, MUI sx styling, styled() MUI extensions, stateless component patterns, and the container/view split. Use when creating new React components, refactoring UI code, deciding where a component belongs, or when asked about component architecture or styling conventions. ---- - -# React Component Architecture - -> **Summary:** FinishLine organizes React components into a shared library (`src/frontend/src/components/`) and page-specific directories (`src/frontend/src/pages/{Feature}/`). Shared components are stateless, prop-driven building blocks. Page components compose them into features, own state, and handle data fetching. - -## Overview - -FinishLine's frontend is built from two layers of components. The **shared component library** contains reusable, stateless UI primitives — buttons, form fields, modals, display blocks, layout shells, and data presentation widgets. These components know nothing about business logic; they receive data through props and notify parents through callbacks. - -**Page-level components** live in feature directories under `src/frontend/src/pages/`. They compose shared components into complete features, own local state (edit mode, modal visibility, active tab), fetch data via React Query hooks, and handle user interactions. Complex pages often use a **container/view split** where a container component manages data fetching and state while a view component handles pure rendering. - -Before building any new component, always check `src/frontend/src/components/` first. The shared library already covers common patterns — detail displays, modals, form fields, buttons, search bars, loading states, progress bars, tabs, and more. Duplicating existing functionality is a common mistake for new developers. - -## Architecture - -``` -src/frontend/src/ -├── components/ ← Shared library -│ ├── NERButton.tsx (styled MUI) -│ ├── NERFormModal.tsx (form wrapper) -│ ├── NERAutocomplete.tsx (controlled input) -│ ├── DetailDisplay.tsx (label + value) -│ ├── PageLayout.tsx (page shell) -│ ├── LoadingIndicator.tsx (loading state) -│ ├── SearchBar.tsx (search input) -│ ├── Toast/ (multi-file) -│ │ ├── Toast.tsx -│ │ └── ToastProvider.tsx -│ └── ... -└── pages/ ← Feature pages - └── ProjectDetailPage/ - ├── ProjectPage.tsx (entry) - ├── DeleteProject.tsx (container) - ├── DeleteProjectView.tsx (view) - ├── ProjectForm/ (edit mode) - └── ProjectViewContainer/ (read mode) - ├── ProjectViewContainer.tsx - ├── ProjectDetails.tsx - ├── WorkPackageSummary.tsx - └── ... -``` - -**Data flow in a typical page:** - -``` -┌──────────┐ React Query ┌───────────┐ -│ Page │──────────────▶│ Container │ -│ (entry) │ hook data │ (state) │ -└──────────┘ └─────┬─────┘ - │ props - ┌─────▼─────┐ - │ View │ - │ (render) │ - └─────┬─────┘ - │ composes - ┌────────────┼────────────┐ - ▼ ▼ ▼ - PageLayout DetailDisplay NERButton - (shared) (shared) (shared) -``` - -## Component Categories - -FinishLine has three distinct component categories. Each has different rules. - -### 1. Shared Functional Components - -Standard React functional components in `src/frontend/src/components/`. These are the most common type. They accept a typed props interface, render MUI components, and return JSX. - -**Examples:** `DetailDisplay`, `NERAutocomplete`, `PageLayout`, `SearchBar`, `InfoBlock`, `NERFormModal`, `ActionsMenu`, `LoadingIndicator` - -### 2. Styled MUI Extensions - -Components created with MUI's `styled()` utility that extend a base MUI component with FinishLine-specific theming. These are thin wrappers — often under 30 lines — that set colors, sizes, and hover states to match the FinishLine design system (red: `#ef4345`). - -**Examples:** `NERButton`, `NERSuccessButton`, `NERFailButton`, `NERSwitch`, `NERProgressBar` - -### 3. Page-Specific Components - -Components that live in a page's directory and are only used by that feature. These include entry-point page components, container/view pairs, and feature-specific sub-components like `WorkPackageSummary` or `ProjectDetails`. - -**Examples:** `ProjectPage`, `DeleteProject` / `DeleteProjectView`, `ProjectViewContainer`, `ProjectDetails` - -## File Locations and Naming - -**Shared components:** `src/frontend/src/components/{ComponentName}.tsx` - -- Single-file components: `NERAutocomplete.tsx`, `DetailDisplay.tsx` -- Multi-file components (rare): `Toast/Toast.tsx`, `Toast/ToastProvider.tsx`, `Link/LinkView.tsx` -- Use a subdirectory only when the component has multiple closely related files - -**Page components:** `src/frontend/src/pages/{FeaturePage}/{ComponentName}.tsx` - -- Entry point: `{Feature}Page.tsx` (e.g., `ProjectPage.tsx`) -- Containers: `{Action}{Feature}.tsx` (e.g., `DeleteProject.tsx`) -- Views: `{Action}{Feature}View.tsx` (e.g., `DeleteProjectView.tsx`) -- Sub-components: descriptive name (e.g., `ProjectDetails.tsx`, `WorkPackageSummary.tsx`) -- Subdirectories for complex tab content (e.g., `ProjectViewContainer/`, `ProjectForm/`) - -**Naming conventions:** - -- PascalCase for all component files and component names -- File name MUST match the default export name -- Prefix shared components with `NER` when they wrap/extend MUI components (e.g., `NERButton`, `NERFormModal`, `NERAutocomplete`) -- Do NOT prefix page-specific components with `NER` - -## Prop Design Conventions - -### TypeScript Interfaces (Required) - -Every component that accepts props MUST define a named TypeScript interface. Never use inline type annotations on the function parameter. - -```tsx -// ✅ CORRECT — named interface -interface DetailDisplayProps { - label: string; - content: string; - paddingRight?: number; - copyButton?: boolean; -} - -const DetailDisplay: React.FC = ({ - label, content, paddingRight = 0, copyButton = false -}) => { ... }; - -// ❌ WRONG — inline type -const DetailDisplay: React.FC<{ - label: string; content: string; -}> = ({ label, content }) => { ... }; - -// ❌ WRONG — no type at all -const DetailDisplay = ({ label, content }) => { ... }; -``` - -**Interface naming:** `{ComponentName}Props` — always. For exported prop types that other files need, export the interface from the component file. - -### Required vs Optional Props - -- Props that the component cannot render without are **required** (no `?`) -- Style overrides, feature flags, and callbacks with sensible defaults are **optional** (`?`) with default values in destructuring -- Use `= defaultValue` in the parameter destructuring, not `defaultProps` - -```tsx -interface SearchBarProps { - searchText: string; // required - setSearchText: (text: string) => void; // required - placeholder?: string; // optional -} - -export const SearchBar = ({ - searchText, - setSearchText, - placeholder = 'Search...' -}: SearchBarProps) => { ... }; -``` - -### Style Override with `sx` - -Shared components that render MUI elements MUST accept an optional `sx` prop to allow callers to apply style overrides: - -```tsx -interface NERAutocompleteProps { - id: string; - options: { label: string; id: string }[]; - onChange: (event: React.SyntheticEvent, value: { ... } | null) => void; - sx?: SxProps; // ← always optional - // ... -} -``` - -The component spreads or merges `sx` into its root element's styles: - -```tsx -const autocompleteStyle = { - backgroundColor: theme.palette.background.default, - width: '100%', - ...sx // caller overrides win -}; -``` - -### Callback Props - -Components that respond to user interactions MUST expose callbacks as props rather than performing side effects internally. Name callbacks descriptively: - -- `onChange`, `onClick`, `onSubmit` — for standard DOM-like events -- `onHide`, `onClose` — for dismissal actions -- `setSearchText`, `setTab` — for controlled state (matching the `useState` setter convention) -- `enterEditMode`, `handleClose` — for domain-specific actions - -### Children - -Components that act as layout wrappers (e.g., `PageLayout`, `InfoBlock`, `NERFormModal`) accept `children: ReactNode`. Use `React.FC` which includes `children` implicitly, or declare it explicitly in the interface. - -### Extending MUI Props - -When wrapping an MUI component, extend its prop type to preserve pass-through capabilities: - -```tsx -interface NERButtonProps extends ButtonProps { - whiteVariant?: boolean; -} -``` - -## Styling Rules - -### MUI `sx` Prop (Preferred) - -All styling MUST use MUI's `sx` prop. The `sx` prop supports theme-aware values, responsive breakpoints, and pseudo-selectors. - -```tsx -// ✅ CORRECT — sx prop - - {label} - - - -``` - -### `styled()` for Reusable Theme Extensions - -Use MUI's `styled()` utility when creating a reusable component that permanently overrides an MUI component's default styling. This is appropriate for design-system primitives, not one-off styling. - -```tsx -import { Button, styled } from '@mui/material'; - -const NERSuccessButton = styled(Button)(({ theme }) => ({ - backgroundColor: theme.palette.success.main, - color: theme.palette.success.contrastText, - '&:hover': { - backgroundColor: theme.palette.success.dark - } -})) as typeof Button; - -export default NERSuccessButton; -``` - -Use `styled()` when: - -- The component is a permanent design-system token (brand buttons, switches, progress bars) -- The styles are static and theme-derived, not dynamic from props -- Multiple consumers will use the same styled version - -### What to Avoid - -- **NEVER use inline `style={{}}`** — use `sx` instead. Legacy components with `style` should be migrated to `sx` when touched. -- **NEVER use CSS modules for new components** — `LoadingIndicator` uses CSS modules as a legacy pattern. New components MUST use `sx` or `styled()`. -- **NEVER use CSS-in-JS libraries** (styled-components, emotion's `css` prop directly) — use MUI's built-in `sx` and `styled()` APIs only. - -### FinishLine Brand Colors - -When referencing brand colors in `styled()` components, use `#ef4345` (FinishLine red). In functional components, prefer theme palette values: - -```tsx -// In styled() components — direct hex is acceptable -backgroundColor: '#ef4345'; - -// In functional components — prefer theme -const theme = useTheme(); -theme.palette.primary.main; -theme.palette.error.main; -theme.palette.success.main; -``` - -## Statelessness and State Management - -### Shared Components: Stateless by Default - -Shared components MUST prefer statelessness. They receive data via props and notify parents via callbacks. They do NOT: - -- Fetch data (no React Query hooks) -- Manage form state (receive `control` from parent via React Hook Form) -- Track UI state that belongs to the parent (modal open/close, edit mode) - -```tsx -// ✅ CORRECT — stateless, parent controls everything -interface SearchBarProps { - searchText: string; - setSearchText: (text: string) => void; - placeholder?: string; -} - -export const SearchBar = ({ searchText, setSearchText, placeholder = 'Search...' }: SearchBarProps) => { - return ( - - setSearchText(e.target.value)} /> - - ); -}; -``` - -The only state allowed in shared components is **transient UI state** that is purely internal to the component's rendering (e.g., `anchorEl` for a dropdown menu position in `ActionsMenu`). - -### Page Components: Own Their State - -Page-level components are where state lives. They use `useState` for UI state, React Query hooks for server data, and React Hook Form for form state: - -```tsx -const ProjectPage: React.FC = ({ wbsNum }) => { - const [editMode, setEditMode] = useState(false); - const { isLoading, isError, data, error } = useSingleProject(wbsNum); - - if (isError) return ; - if (isLoading || !data) return ; - - if (editMode) { - return setEditMode(false)} />; - } - return setEditMode(true)} />; -}; -``` - -### The `useEffect` Rule - -`useEffect` MUST NOT be used unless it is for one of these cases: - -1. **External subscriptions** — WebSocket connections, event listeners on `window`/`document` -2. **Timers** — `setTimeout`, `setInterval`, `requestAnimationFrame` -3. **Non-React library integration** — initializing a chart library, D3 bindings, imperative DOM APIs - -Do NOT use `useEffect` for: - -- Deriving state from props (use computed values or `useMemo`) -- Syncing React state with other React state (restructure state instead) -- Responding to prop changes (use event handlers or key-based remounting) - -> **Legacy note:** Some existing components (e.g., `FullPageTabs`) use `useEffect` to sync with browser navigation state. This is acceptable in legacy code but MUST NOT be replicated in new components. New components should use router hooks or event handlers directly. - -## The Container/View Pattern - -For components with complex interactions (forms, delete confirmations, multi-step workflows), split into a **container** that manages logic and a **view** that handles rendering. - -### Container - -- Handles data fetching and mutation hooks -- Manages loading/error states -- Calls toast notifications on success/error -- Passes data and callbacks down as props - -```tsx -// DeleteProject.tsx (container) -interface DeleteProjectProps { - modalShow: boolean; - handleClose: () => void; - wbsNum: WbsNumber; -} - -const DeleteProject: React.FC = ({ modalShow, handleClose, wbsNum }) => { - const toast = useToast(); - const { isLoading, isError, error, mutateAsync } = useDeleteProject(); - - const handleConfirm = async ({ wbsNum }: DeleteProjectInputs) => { - try { - await mutateAsync(validateWBS(wbsNum)); - handleClose(); - toast.success(`Project #${wbsPipe(wbsNum)} Deleted!`); - } catch (e) { - if (e instanceof Error) toast.error(e.message); - } - }; - - if (isLoading) return ; - if (isError) return ; - - return ; -}; -``` - -### View - -- Pure rendering only — no hooks other than `useForm` -- Receives all data and callbacks via props -- Owns form setup (schema, `useForm`, validation) when it is a form view - -```tsx -// DeleteProjectView.tsx (view) -interface DeleteProjectViewProps { - project: WbsNumber; - modalShow: boolean; - onHide: () => void; - onSubmit: (data: DeleteProjectInputs) => Promise; -} - -const DeleteProjectView: React.FC = ({ - project, modalShow, onHide, onSubmit -}) => { - const { handleSubmit, control, reset, formState } = useForm({ - resolver: yupResolver(schema), - defaultValues: { wbsNum: '' }, - mode: 'onChange' - }); - - return ( - - {/* form content */} - - ); -}; -``` - -### When to Use Container/View - -Use the container/view split when a component does **both** data fetching/mutation **and** has non-trivial rendering logic. Simple components that just display fetched data (like `ProjectDetails`) can combine both in one file — the split is for managing complexity, not a rigid rule. - -## When to Create a Shared Component - -A component belongs in `src/frontend/src/components/` when: - -1. **Two or more pages need it** — if you find yourself copying a component between page directories, extract it to shared -2. **It is a general UI pattern** — detail displays, modals, buttons, form fields, status pills, search inputs, loading states -3. **It has no domain-specific business logic** — shared components know about visual presentation, not Work Packages or Change Requests - -A component stays in its page directory when: - -1. **Only one feature uses it** — `WorkPackageSummary` is only relevant to the project detail page -2. **It contains feature-specific business logic** — `BOMTab` composes shared components but encodes BOM-specific display rules -3. **It is a container** — containers with data-fetching hooks and mutation logic are always page-specific - -**When in doubt:** Start page-specific. Extract to shared when a second consumer appears. Premature extraction creates unused abstractions. - -## Step-by-Step: Creating a New Shared Component - -1. **Check the existing library.** Search `src/frontend/src/components/` for similar functionality. If something close exists, extend it with new props rather than creating a duplicate. - -2. **Define the props interface.** Name it `{ComponentName}Props`. Include `sx?: SxProps` if the component renders MUI elements. Make props that have sensible defaults optional. - -3. **Write a stateless functional component.** Use `React.FC` typing. Destructure props with defaults. Do not add state unless absolutely necessary for transient UI behavior. - -4. **Style with `sx`.** Use the `sx` prop on MUI components. Use `useTheme()` for theme-aware values. Merge caller's `sx` override into the root element. - -5. **Export as default.** One component per file, default export, file name matches component name. - -```tsx -import { Box, Typography, SxProps, Theme, useTheme } from '@mui/material'; - -interface StatusBadgeProps { - label: string; - color: 'success' | 'error' | 'warning'; - sx?: SxProps; -} - -const StatusBadge: React.FC = ({ label, color, sx }) => { - const theme = useTheme(); - - return ( - - {label} - - ); -}; - -export default StatusBadge; -``` - -## Key Rules - -- Every component that accepts props MUST define a named `{ComponentName}Props` interface — NEVER use inline types -- Shared components MUST be stateless — receive data via props, notify parents via callbacks -- NEVER use `useEffect` unless it is for an external subscription, timer, or non-React library integration -- ALWAYS use MUI `sx` prop for styling — NEVER use inline `style={{}}` -- ALWAYS check `src/frontend/src/components/` before building a new component -- Shared components MUST NOT contain data-fetching hooks (React Query) or mutation logic -- ALWAYS accept `sx?: SxProps` on shared components that render MUI elements -- One component per file, default export, file name matches component name -- Prefix shared MUI wrapper components with `NER` (e.g., `NERButton`, `NERModal`) - -## Common Mistakes - -- **Building a component that already exists.** The shared library has 50+ components. Search before creating. Common ones missed: `DetailDisplay` (label-value pairs), `InfoBlock` (titled sections), `NERFormModal` (form dialogs), `ActionsMenu` (dropdown action buttons). - -- **Using `useEffect` to derive state.** If you need to compute something from props, use a local variable or `useMemo`. If you need to "reset" state when a prop changes, use a `key` prop on the component instead. - -- **Using inline `style` instead of `sx`.** MUI's `sx` supports theme values, responsive breakpoints, and pseudo-selectors. Inline `style` does not. - -- **Putting data-fetching in a shared component.** Shared components render data — they don't fetch it. If your shared component needs a React Query hook, it should be a page component instead, or the data should be passed as a prop. - -- **Defining props inline.** Always create a named interface. This makes props discoverable, exportable, and consistent across the codebase. - -- **Creating a shared component too early.** Start page-specific. Extract when a second page needs the same component. Unused shared components are clutter. - -## Reference Files - -**Shared components (good examples of prop design and statelessness):** - -- `src/frontend/src/components/NERAutocomplete.tsx` — Controlled input with full props interface, `sx` override, form error integration -- `src/frontend/src/components/DetailDisplay.tsx` — Minimal stateless display component with optional features -- `src/frontend/src/components/PageLayout.tsx` — Layout shell with children, optional header elements, breadcrumbs -- `src/frontend/src/components/SearchBar.tsx` — Controlled search with `styled()` sub-components and callback pattern -- `src/frontend/src/components/ActionsMenu.tsx` — Shared component with allowable transient UI state (menu anchor) - -**Styled MUI extensions:** - -- `src/frontend/src/components/NERSuccessButton.tsx` — Clean `styled()` theme extension -- `src/frontend/src/components/NERSwitch.tsx` — Complex `styled()` with pseudo-selectors - -**Page components (good examples of composition and container/view):** - -- `src/frontend/src/pages/ProjectDetailPage/ProjectPage.tsx` — Entry point with loading/error handling and edit mode toggle -- `src/frontend/src/pages/ProjectDetailPage/DeleteProject.tsx` — Container with mutation logic and toast handling -- `src/frontend/src/pages/ProjectDetailPage/DeleteProjectView.tsx` — Pure form view with `NERFormModal` and React Hook Form -- `src/frontend/src/pages/ProjectDetailPage/ProjectViewContainer/ProjectViewContainer.tsx` — Complex page composing many shared components - -## Checklist - -- [ ] Searched `src/frontend/src/components/` for existing components before creating new ones -- [ ] Props interface is named `{ComponentName}Props` (not inline) -- [ ] Component is `React.FC` with default export matching file name -- [ ] Shared component is stateless (no data fetching, no `useEffect`, no owned UI state beyond transient menu anchors) -- [ ] Styling uses `sx` prop, not inline `style` -- [ ] Shared components that render MUI elements accept optional `sx?: SxProps` -- [ ] Callbacks are exposed as props, not handled internally -- [ ] `styled()` is only used for permanent design-system tokens, not one-off styling -- [ ] Page components handle loading/error states with `LoadingIndicator` and `ErrorPage` -- [ ] Complex interactions use the container/view split - -## Migration Notes - -> This section describes how this pattern differs from older code in the -> codebase. New code MUST follow the patterns above. When modifying existing -> files, update them to match these patterns where practical. - -**Inline `style` → `sx`:** Some older components (e.g., `WarningBanner`) use `style={{}}` instead of MUI's `sx` prop. When touching these files, migrate to `sx`. - -**CSS Modules → `sx`/`styled()`:** `LoadingIndicator` uses a CSS module (`loading-indicator.module.css`). New components MUST NOT use CSS modules. When significantly refactoring components that use CSS modules, migrate to `sx` or `styled()`. - -**`useEffect` for router sync:** `FullPageTabs` uses `useEffect` to sync tab state with the browser URL. This is acceptable as legacy code but MUST NOT be replicated. New components should use router hooks or event handlers directly. diff --git a/.claude/skills/general-practices/repository-overview/SKILL.md b/.claude/skills/general-practices/repository-overview/SKILL.md deleted file mode 100644 index 28359d707e..0000000000 --- a/.claude/skills/general-practices/repository-overview/SKILL.md +++ /dev/null @@ -1,350 +0,0 @@ ---- -name: repository-overview -description: High-level overview of the FinishLine monorepo structure, tech stack, tools, and how they work together. Use when onboarding to the codebase, asking about the project structure, wondering what technology FinishLine uses, asking where files live, or needing to understand how the frontend, backend, and shared packages relate to each other. ---- - -# Repository Overview - -> **Summary:** FinishLine is a TypeScript monorepo with a React frontend, Express backend, and shared type package, managed with Yarn workspaces and built for Northeastern Electric Racing's project management needs. - -## What is FinishLine? - -FinishLine is a full-stack ERP and project management application built for **Northeastern Electric Racing (NER)**, a student engineering organization at Northeastern University that designs, builds, and races electric vehicles. The platform manages work breakdown structures, change requests, reimbursements, bill of materials, user onboarding, calendar events, supply chain operations, team management, and more. - -The primary users are engineering students, team leads, and club advisors. NER is structured into subteams (mechanical, electrical, software, business, etc.) with roles including guests, members, leadership, heads, admins, and app admins. FinishLine supports multi-tenant organizations — all data is scoped by `organizationId`. - -## Monorepo Structure - -FinishLine uses **Yarn workspaces** to manage three packages in a single repository: - -``` -src/ -├── backend/ # Express API server (Node.js) -├── frontend/ # React SPA (Vite) -└── shared/ # Common TypeScript types and utilities -``` - -The root `package.json` declares these workspaces and provides top-level scripts that orchestrate builds, tests, and development servers. The `shared` package MUST be built before the frontend or backend can use it, because they import its compiled output. - -### Backend (`src/backend/`) - -The backend is an **Express 5** server using **Prisma ORM** with **PostgreSQL**. It follows a layered architecture: - -``` -src/backend/ -├── index.ts # App entry: middleware, route registration, error handler -├── src/ -│ ├── routes/ # Express route definitions with express-validator -│ ├── controllers/ # Thin request handlers — extract data, call service, return response -│ ├── services/ # Business logic — static class methods, filter by organizationId -│ ├── prisma/ # Schema, migrations, seed data, Prisma client singleton -│ ├── prisma-query-args/# Reusable Prisma select/include argument objects -│ ├── transformers/ # Convert Prisma models to API response shapes (shared types) -│ ├── integrations/ # External service clients (Slack) -│ └── utils/ # Auth middleware, custom exceptions, validation, helpers -└── tests/ - ├── unit/ # Service-level unit tests (vitest) - ├── integration/ # Integration tests - ├── test-data/ # Test fixtures - └── test-utils.ts # Shared test helpers -``` - -Key technology choices: - -- **Express 5** for HTTP routing and middleware -- **Prisma 6** as the ORM with PostgreSQL -- **express-validator** for request input validation on routes -- **express-jwt** and **jsonwebtoken** for JWT-based authentication -- **Vitest** for unit and integration testing -- **Multer** for file uploads -- **Slack Web API** for Slack integration -- **Google APIs** for Google Calendar/Drive integration - -### Frontend (`src/frontend/`) - -The frontend is a **React 19** single-page application built with **Vite**: - -``` -src/frontend/ -├── src/ -│ ├── index.tsx # ReactDOM entry point -│ ├── app/ # Context providers, routing, auth wrappers -│ ├── pages/ # Route-level page components (one directory per feature) -│ ├── components/ # Reusable UI components (NERFormModal, NERDataGrid, etc.) -│ ├── hooks/ # React Query hooks wrapping API calls -│ ├── apis/ # Axios API call functions with response transformers -│ │ └── transformers/ # Frontend-specific response transformers -│ ├── layouts/ # Layout components -│ ├── utils/ # Routes, URL builders, pipes, types, axios config -│ ├── stylesheets/ # SCSS stylesheets -│ └── tests/ # Component, hook, and page tests (vitest) -``` - -Key technology choices: - -- **React 19** with functional components and hooks -- **Vite 6** for dev server and production builds -- **Material-UI (MUI) v6** for the component library and styling -- **React Query v3** (`react-query` 3.17.0) for server state management -- **React Hook Form v7** with **Yup** validation for forms -- **React Router DOM v5** for client-side routing -- **Axios** for HTTP requests to the backend -- **Recharts** and **Chart.js** for data visualization -- **date-fns** and **dayjs** for date manipulation -- **Vitest** for testing with React Testing Library - -### Shared (`src/shared/`) - -The shared package contains **TypeScript type definitions** and **utility functions** used by both the frontend and backend: - -``` -src/shared/ -├── index.ts # Re-exports everything -└── src/ - ├── types/ # TypeScript interfaces for API contracts - │ ├── project-types.ts - │ ├── user-types.ts - │ ├── calendar-types.ts - │ ├── change-request-types.ts - │ ├── finance-types.ts - │ ├── reimbursement-requests-types.ts - │ ├── work-package-types.ts - │ ├── team-types.ts - │ ├── bom-types.ts - │ ├── statistics-types.ts - │ ├── part-review.types.ts - │ └── ... - ├── backend-supports/ # Backend-specific shared logic - ├── date-utils.ts # Shared date utilities - ├── permission-utils.ts # Role/permission checking - ├── validate-wbs.ts # WBS number validation - ├── utils.ts # General utilities - └── word-count.ts # Word count utility -``` - -Types are imported throughout the codebase as: - -```typescript -import { Project, User, WbsNumber } from 'shared'; -``` - -The shared package compiles to `dist/` via TypeScript and is referenced by the other packages through Yarn workspace resolution. - -## How the Pieces Work Together - -### End-to-End Data Flow - -A typical request flows through the system like this: - -``` -Page Component - │ - ▼ -Hook (useQuery / useMutation) - │ - ▼ -API function (Axios) - │ - ── HTTP request ──▶ Route (validation) - │ - ▼ - Controller - │ - ▼ - Service (business logic) - │ - ▼ - Prisma (DB + transaction) - │ - ▼ - Transformer (Prisma → shared type) - │ - ◀── HTTP response ─── - │ - ▼ -Frontend transformer → shared type - │ - ▼ -Hook returns data to component -``` - -Shared types define the API contract at every boundary. - -1. A **React page component** renders UI and calls a **hook** (`useQuery` for reads, `useMutation` for writes). -2. The hook calls an **API function** in `src/frontend/src/apis/` which uses **Axios** to make an HTTP request. For reads, the API function applies a **frontend transformer** to convert the raw response into the shared type. -3. The request hits an **Express route** which runs **express-validator** middleware for input validation, then calls the **controller**. -4. The **controller** is a thin layer: it extracts data from the request (`req.body`, `req.params`, `req.currentUser`, `req.organization`), calls the **service** method, and returns the result with an HTTP status code. -5. The **service** contains the business logic. It validates permissions, enforces business rules, queries the database via **Prisma**, and returns data. For responses, it uses a **backend transformer** to convert Prisma models into the shared API types. -6. **Shared types** (`src/shared/src/types/`) define the data shapes at every boundary. The backend transformer produces these types; the frontend API function expects them. - -### Authentication and Multi-Tenancy - -Every request (except login and health check) passes through middleware defined in `src/backend/index.ts`: - -1. **JWT validation** (`requireJwtProd` or `requireJwtDev`) — verifies the user's identity and stores `userId` in `res.locals`. -2. **`getUserAndOrganization`** — looks up the user and organization from the database, verifies the user belongs to the organization, and attaches both to `req.currentUser` and `req.organization`. - -This means every controller and service method has access to the authenticated user and their organization. Services MUST filter all database queries by `organizationId` to enforce data isolation. - -On the frontend, the Axios interceptor in `src/frontend/src/utils/axios.ts` automatically attaches the `organizationId` header and the authorization token to every request. - -### Context Providers - -The frontend wraps the app in a provider hierarchy (see `src/frontend/src/app/AppMain.tsx` → `AppContext.tsx`): - -``` -ClarityProvider → Analytics (Microsoft Clarity) - AppContext → Composed provider wrapper - QueryClientProvider → React Query cache - OrganizationContext → Current organization state - AuthContext → Current user authentication - ThemeContext → MUI theme (light/dark) - HomePageProvider → Home page state - ToastProvider → Toast notifications - BrowserRouter → React Router v5 - OAuthProvider → Google OAuth -``` - -### HTTP Method Convention - -FinishLine uses an unconventional HTTP method pattern: **GET for reads, POST for everything else** (creates, updates, and deletes). The backend does not use PUT, PATCH, or DELETE methods. - -## Key File Location Reference - -When looking for code related to a specific feature, files follow a consistent naming pattern across the stack: - -| Layer | Path Pattern | Example (Calendar) | -| ----------------- | ----------------------------------------------------------- | ------------------------- | -| Routes | `src/backend/src/routes/{feature}.routes.ts` | `calendar.routes.ts` | -| Controllers | `src/backend/src/controllers/{feature}.controllers.ts` | `calendar.controllers.ts` | -| Services | `src/backend/src/services/{feature}.services.ts` | `calendar.services.ts` | -| Prisma Query Args | `src/backend/src/prisma-query-args/{feature}.query-args.ts` | `calendar.query-args.ts` | -| Transformers | `src/backend/src/transformers/{feature}.transformer.ts` | `calendar.transformer.ts` | -| Backend Utils | `src/backend/src/utils/{feature}.utils.ts` | `calendar.utils.ts` | -| Backend Tests | `src/backend/tests/unit/{feature}.test.ts` | `calendar.test.ts` | -| Shared Types | `src/shared/src/types/{feature}-types.ts` | `calendar-types.ts` | -| Frontend APIs | `src/frontend/src/apis/{feature}.api.ts` | `calendar.api.ts` | -| Frontend Hooks | `src/frontend/src/hooks/{feature}.hooks.ts` | `calendar.hooks.ts` | -| Frontend Pages | `src/frontend/src/pages/{FeaturePage}/` | `CalendarPage/` | -| Frontend Utils | `src/frontend/src/utils/{feature}.utils.ts` | `calendar.utils.ts` | -| Frontend Tests | `src/frontend/src/tests/pages/{FeaturePage}/` | — | -| URL Builders | `src/frontend/src/utils/urls.ts` | (all in one file) | -| Frontend Routes | `src/frontend/src/utils/routes.ts` | (all in one file) | - -## Feature Areas - -FinishLine covers the following major feature areas. Each has its own slice through the full stack (routes, services, hooks, pages, types): - -- **Work Breakdown Structure (WBS):** Projects and Work Packages with status tracking, description bullets, and stage gates -- **Change Requests:** Formal approval workflow for scope, timeline, and budget changes (multiple CR types: standard, activation, stage gate, budget) -- **Finance:** Reimbursement requests with multi-step approval chains, vendors, sponsors, sponsor tiers, account codes, index codes -- **Calendar:** Events, event types, calendars, shops, machinery, schedule slots, and a confirmation/scheduling workflow -- **Teams & Users:** Role-based access control, team assignments, team types, user settings, secure settings, schedule settings -- **Onboarding:** Checklists with ordered items for new member onboarding -- **Parts & BOM:** Part creation, part review workflow (submissions, review requests, reviews), bill of materials (materials, assemblies, manufacturers, units) -- **Statistics:** Custom graphs, graph collections, and dashboard analytics -- **Retrospective:** Timelines and budget retrospectives for completed work -- **Recruitment:** Milestones and FAQs for the recruitment pipeline -- **Notifications & Announcements:** Push notifications, pop-ups, and announcements -- **Tasks:** Task tracking tied to WBS elements with status and priority -- **Gantt:** Timeline visualization for projects and work packages -- **Organizations:** Multi-tenant organization settings, useful links, featured projects, images, contacts - -## Development Environment - -### Prerequisites - -FinishLine requires **Docker** for the PostgreSQL database regardless of how you run the application code. You MUST have Docker installed and running before starting development. - -### Initial Setup - -First time setup (or after pulling new dependencies): - -```bash -yarn install # Install all workspace dependencies -yarn prisma:generate # Generate the Prisma client from the schema -``` - -### Database Setup - -The PostgreSQL database always runs in a Docker container. The `yarn database:setup` command handles everything: it writes the `DATABASE_URL` to `src/backend/.env`, starts a PostgreSQL container named `finishline` on port 5432, creates the `nerpm` database, and runs Prisma migrations with seed data: - -```bash -yarn database:setup # One-time: create Postgres container + seed DB -``` - -After initial setup, the container persists. If you restart your machine, start it again with `docker start finishline`. - -### Running the Application - -You have two options for running the frontend and backend: on your host machine or in Docker containers. Either way, they connect to the same PostgreSQL container. - -**Option A: Host machine (recommended for faster iteration)** - -```bash -yarn start # Builds shared, starts backend (nodemon, port 3001) - # + frontend (vite, port 3000) concurrently -``` - -Or run them individually: - -```bash -yarn frontend # Frontend dev server on port 3000 -yarn backend:dev # Backend with nodemon on port 3001 -yarn workspace shared build # Rebuild shared (required after changing shared types) -``` - -**Option B: Docker containers** - -```bash -yarn docker:start # Start frontend + backend + DB containers -yarn docker:dev # Full docker dev environment with watch mode -yarn docker:i # Install deps inside containers -``` - -### Database Commands - -These commands manage the Prisma schema and database state: - -```bash -yarn prisma:generate # Regenerate Prisma client — run after ANY schema.prisma change -yarn prisma:migrate # Create and apply a new migration — run after adding/changing - # models, fields, enums, or relations in schema.prisma -yarn prisma:reset # Drop the database, re-run all migrations, and re-seed — useful - # when your local DB is in a bad state or you want a clean slate -yarn prisma:studio # Open Prisma Studio GUI — a visual database browser for debugging -``` - -### Testing - -Tests run against a **separate** PostgreSQL container on port 5433 so they don't interfere with your development database. You MUST run the setup script before testing and the teardown script after: - -```bash -yarn test:setup # Spins up a test Postgres container (port 5433) - # and adds a test DATABASE_URL to .env - -yarn test # Run all tests (backend then frontend) -yarn test:backend # Backend unit tests only (vitest) -yarn test:frontend # Frontend tests only (vitest) - -yarn test:teardown # Stops and removes the test container, - # removes the test DATABASE_URL from .env -``` - -The setup script appends a second `DATABASE_URL` pointing at port 5433 to `src/backend/.env`. Prisma uses the last `DATABASE_URL` in the file, so tests hit the test database while the line is present. The teardown script removes it, restoring the original dev database URL. If you skip teardown, your dev server will point at the (stopped) test database and fail to connect. - -### Code Quality - -```bash -yarn lint # ESLint -yarn prettier-check # Prettier formatting check -yarn tsc-check # TypeScript type checking (frontend + backend) -``` - -## ESLint Rules - -The project enforces strict ESLint rules including: `guard-for-in`, `prefer-arrow-callback`, `eqeqeq` (strict equality), `no-var`, `prefer-const`, `prefer-destructuring`, `object-shorthand`, `no-else-return`, `no-lonely-if`, `no-throw-literal`, and `prefer-spread`. See the root `package.json` `eslintConfig` section for the full configuration. - -## License - -FinishLine is licensed under **GNU AGPLv3**. Source files include a license header comment. diff --git a/docs-site/README.md b/docs-site/README.md index 1759795432..e4a9838f95 100644 --- a/docs-site/README.md +++ b/docs-site/README.md @@ -186,6 +186,7 @@ The sidebar navigation is **automatically generated** from the `docs/` folder st The sidebar regenerates automatically when you run `yarn docs:dev` or `yarn docs:build`. You can also manually regenerate it: + ```bash yarn generate-sidebar ``` diff --git a/docs-site/babel.config.js b/docs-site/babel.config.js index e00595dae7..6bf8d26f14 100644 --- a/docs-site/babel.config.js +++ b/docs-site/babel.config.js @@ -1,3 +1,3 @@ module.exports = { - presets: [require.resolve('@docusaurus/core/lib/babel/preset')], + presets: [require.resolve('@docusaurus/core/lib/babel/preset')] }; diff --git a/docs-site/docs/general-practices/backend-endpoints.md b/docs-site/docs/general-practices/backend-endpoints.md index 6cc6782f20..672223c372 100644 --- a/docs-site/docs/general-practices/backend-endpoints.md +++ b/docs-site/docs/general-practices/backend-endpoints.md @@ -60,15 +60,15 @@ If a service throws an exception, it bubbles up through the controller's `next(e ## File Locations -| Layer | Path | Naming | -|-------|------|--------| -| Entry point | `src/backend/index.ts` | — | -| Routes | `src/backend/src/routes/{feature}.routes.ts` | `{feature}Router` | -| Controllers | `src/backend/src/controllers/{feature}.controllers.ts` | `{Feature}Controller` class | -| Services | `src/backend/src/services/{feature}.services.ts` | `{Feature}Service` class | -| Validation | `src/backend/src/utils/validation.utils.ts` | Shared validators | -| Errors | `src/backend/src/utils/errors.utils.ts` | `HttpException` subclasses | -| Express types | `src/backend/custom.d.ts` | `currentUser` and `organization` on `Request` | +| Layer | Path | Naming | +| ------------- | ------------------------------------------------------ | --------------------------------------------- | +| Entry point | `src/backend/index.ts` | — | +| Routes | `src/backend/src/routes/{feature}.routes.ts` | `{feature}Router` | +| Controllers | `src/backend/src/controllers/{feature}.controllers.ts` | `{Feature}Controller` class | +| Services | `src/backend/src/services/{feature}.services.ts` | `{Feature}Service` class | +| Validation | `src/backend/src/utils/validation.utils.ts` | Shared validators | +| Errors | `src/backend/src/utils/errors.utils.ts` | `HttpException` subclasses | +| Express types | `src/backend/custom.d.ts` | `currentUser` and `organization` on `Request` | For query args and transformers, see the [query-args-and-transformers](./query-args-and-transformers) skill. @@ -77,11 +77,13 @@ For query args and transformers, see the [query-args-and-transformers](./query-a The full URL path for any endpoint is the **combination** of the base path registered in `src/backend/index.ts` and the route path in the router file. This is a very common source of confusion. For example, if `index.ts` registers: + ```typescript app.use('/calendar', calendarRouter); ``` And the router defines: + ```typescript calendarRouter.post('/shop/create', ...); ``` @@ -100,13 +102,8 @@ Add validation rules using `express-validator` and the helpers from `validation. // src/backend/src/routes/calendar.routes.ts import express from 'express'; import { body } from 'express-validator'; -import { - nonEmptyString, - isDate, - validateInputs -} from '../utils/validation.utils.js'; -import CalendarController - from '../controllers/calendar.controllers.js'; +import { nonEmptyString, isDate, validateInputs } from '../utils/validation.utils.js'; +import CalendarController from '../controllers/calendar.controllers.js'; const calendarRouter = express.Router(); @@ -132,6 +129,7 @@ export default calendarRouter; - URL params use `param()`, query strings use `query()`, body fields use `body()`. **When to abstract validators:** Keep validation inline in the route by default. Only extract validators into `validation.utils.ts` when: + - The request body contains a **nested object** that is itself a known entity (e.g., a work package embedded inside a project create payload). Create a named validator array like `workPackageProposedChangesValidators`. - The **same set of validations** is repeated across multiple routes (e.g., `descriptionBulletsValidators` used in both work package and project routes). @@ -143,8 +141,7 @@ If creating a brand new feature router, register it in `src/backend/index.ts`: ```typescript // src/backend/index.ts -import calendarRouter - from './src/routes/calendar.routes.js'; +import calendarRouter from './src/routes/calendar.routes.js'; // ... after getUserAndOrganization middleware ... app.use('/calendar', calendarRouter); @@ -159,30 +156,18 @@ Controllers follow a rigid structure: try/catch, extract request data, call serv ```typescript // src/backend/src/controllers/calendar.controllers.ts import { NextFunction, Request, Response } from 'express'; -import CalendarService - from '../services/calendar.services.js'; +import CalendarService from '../services/calendar.services.js'; export default class CalendarController { - static async createShop( - req: Request, - res: Response, - next: NextFunction - ) { + static async createShop(req: Request, res: Response, next: NextFunction) { try { - const { name, description, dateEstablished } - = req.body; + const { name, description, dateEstablished } = req.body; // Parse date strings to Date objects // before passing to the service const parsedDate = new Date(dateEstablished); - const shop = await CalendarService.createShop( - req.currentUser, - name, - description, - parsedDate, - req.organization - ); + const shop = await CalendarService.createShop(req.currentUser, name, description, parsedDate, req.organization); res.status(200).json(shop); } catch (error: unknown) { @@ -211,16 +196,10 @@ Services contain all business logic. // src/backend/src/services/calendar.services.ts import { User, Shop, notGuest } from 'shared'; import prisma from '../prisma/prisma.js'; -import { - AccessDeniedGuestException, - HttpException -} from '../utils/errors.utils.js'; -import { shopTransformer } - from '../transformers/calendar.transformer.js'; -import { getShopQueryArgs } - from '../prisma-query-args/shop.query-args.js'; -import { userHasPermission } - from '../utils/users.utils.js'; +import { AccessDeniedGuestException, HttpException } from '../utils/errors.utils.js'; +import { shopTransformer } from '../transformers/calendar.transformer.js'; +import { getShopQueryArgs } from '../prisma-query-args/shop.query-args.js'; +import { userHasPermission } from '../utils/users.utils.js'; import { Organization } from '@prisma/client'; export default class CalendarService { @@ -246,16 +225,8 @@ export default class CalendarService { organization: Organization ): Promise { // 1. Permission check - if ( - !(await userHasPermission( - submitter.userId, - organization.organizationId, - notGuest - )) - ) { - throw new AccessDeniedGuestException( - 'create shops' - ); + if (!(await userHasPermission(submitter.userId, organization.organizationId, notGuest))) { + throw new AccessDeniedGuestException('create shops'); } // 2. Business rule validation (inline select) @@ -269,10 +240,7 @@ export default class CalendarService { }); if (duplicate) { - throw new HttpException( - 400, - 'A shop with that name already exists' - ); + throw new HttpException(400, 'A shop with that name already exists'); } // 3. Database write (query args for response) @@ -314,22 +282,20 @@ Every write endpoint (and some sensitive reads) needs a permission check at the ```typescript import { - notGuest, // members and above - isLeadership, // leads and above - isHead, // heads and above - isAdmin // admins and app-admins only + notGuest, // members and above + isLeadership, // leads and above + isHead, // heads and above + isAdmin // admins and app-admins only } from 'shared'; if ( !(await userHasPermission( submitter.userId, organization.organizationId, - isHead // choose the right level + isHead // choose the right level )) ) { - throw new AccessDeniedAdminOnlyException( - 'create event types' - ); + throw new AccessDeniedAdminOnlyException('create event types'); } ``` @@ -348,16 +314,16 @@ Match the exception class to the level: `AccessDeniedGuestException` for `notGue Services throw exceptions from `src/backend/src/utils/errors.utils.ts`. The global `errorHandler` middleware catches them. -| Exception | Status | When to Use | -|-----------|--------|-------------| -| `HttpException(status, msg)` | any | General-purpose with custom status | -| `NotFoundException(name, id)` | 404 | Entity not found | -| `DeletedException(name, id)` | 404 | Entity is soft-deleted | -| `AccessDeniedException(msg?)` | 403 | Generic permission failure | -| `AccessDeniedAdminOnlyException(action)` | 403 | Non-admin attempting admin action | -| `AccessDeniedMemberException(action)` | 403 | Guest/member attempting restricted action | -| `AccessDeniedGuestException(action)` | 403 | Guest attempting non-guest action | -| `InvalidOrganizationException(item)` | 400 | Entity not in current org | +| Exception | Status | When to Use | +| ---------------------------------------- | ------ | ----------------------------------------- | +| `HttpException(status, msg)` | any | General-purpose with custom status | +| `NotFoundException(name, id)` | 404 | Entity not found | +| `DeletedException(name, id)` | 404 | Entity is soft-deleted | +| `AccessDeniedException(msg?)` | 403 | Generic permission failure | +| `AccessDeniedAdminOnlyException(action)` | 403 | Non-admin attempting admin action | +| `AccessDeniedMemberException(action)` | 403 | Guest/member attempting restricted action | +| `AccessDeniedGuestException(action)` | 403 | Guest attempting non-guest action | +| `InvalidOrganizationException(item)` | 400 | Entity not in current org | The `name` parameter for `NotFoundException` and `DeletedException` MUST be one of the values in the `ExceptionObjectNames` type union in `errors.utils.ts`. Add your entity to that type if it's not listed. @@ -365,17 +331,17 @@ The `name` parameter for `NotFoundException` and `DeletedException` MUST be one `src/backend/src/utils/validation.utils.ts` provides reusable validation chains: -| Helper | Validates | -|--------|-----------| -| `nonEmptyString(body('x'))` | Non-empty string | -| `intMinZero(body('x'))` | Integer ≥ 0, not a string | -| `decimalMinZero(body('x'))` | Decimal ≥ 0 | -| `isDate(body('x'))` | Parseable date string | -| `isOptionalDate(body('x'))` | Optional parseable date | -| `isRole(body('x'))` | Valid `RoleEnum` value | -| `isStatus(body('x'))` | Valid `WbsElementStatus` | -| `isEventStatus(body('x'))` | Valid `Event_Status` | -| `validateInputs` | Runs validation, returns 400 | +| Helper | Validates | +| --------------------------- | ---------------------------- | +| `nonEmptyString(body('x'))` | Non-empty string | +| `intMinZero(body('x'))` | Integer ≥ 0, not a string | +| `decimalMinZero(body('x'))` | Decimal ≥ 0 | +| `isDate(body('x'))` | Parseable date string | +| `isOptionalDate(body('x'))` | Optional parseable date | +| `isRole(body('x'))` | Valid `RoleEnum` value | +| `isStatus(body('x'))` | Valid `WbsElementStatus` | +| `isEventStatus(body('x'))` | Valid `Event_Status` | +| `validateInputs` | Runs validation, returns 400 | For complex reusable validators, spread them: `...descriptionBulletsValidators`. diff --git a/docs-site/docs/general-practices/query-args-and-transformers.md b/docs-site/docs/general-practices/query-args-and-transformers.md index 20f69b43fc..7544774e8c 100644 --- a/docs-site/docs/general-practices/query-args-and-transformers.md +++ b/docs-site/docs/general-practices/query-args-and-transformers.md @@ -45,11 +45,11 @@ This separation exists because Prisma's auto-generated types (column names, nest ## File Locations -| Layer | Path | Naming | -|-------|------|--------| -| Query args | `src/backend/src/prisma-query-args/{feature}.query-args.ts` | `get{Entity}QueryArgs` | -| Transformers | `src/backend/src/transformers/{feature}.transformer.ts` | `{entity}Transformer` | -| Shared types | `src/shared/src/types/{feature}-types.ts` | TypeScript interfaces | +| Layer | Path | Naming | +| ------------ | ----------------------------------------------------------- | ---------------------- | +| Query args | `src/backend/src/prisma-query-args/{feature}.query-args.ts` | `get{Entity}QueryArgs` | +| Transformers | `src/backend/src/transformers/{feature}.transformer.ts` | `{entity}Transformer` | +| Shared types | `src/shared/src/types/{feature}-types.ts` | TypeScript interfaces | ## Query Args @@ -62,12 +62,9 @@ Every query args file follows the same pattern: export a type alias using `Retur import { Prisma } from '@prisma/client'; import { getUserQueryArgs } from './user.query-args.js'; -export type ShopQueryArgs = - ReturnType; +export type ShopQueryArgs = ReturnType; -export const getShopQueryArgs = ( - organizationId: string -) => +export const getShopQueryArgs = (organizationId: string) => Prisma.validator()({ include: { userCreated: getUserQueryArgs(organizationId) @@ -108,9 +105,7 @@ A good example of selective fetching is `getWorkPackagePreviewQueryArgs`, which ```typescript export const getWorkPackagePreviewQueryArgs = () => - Prisma.validator< - Prisma.Work_PackageDefaultArgs - >()({ + Prisma.validator()({ select: { blockedBy: true, wbsElement: { @@ -151,10 +146,12 @@ export const getWorkPackagePreviewQueryArgs = () => Be very careful about nested query args. Every level of nesting adds database joins and increases query cost. Only include nested relations when the transformer actually needs that data to satisfy the shared type. **Good reasons to nest:** + - The shared type has a `userCreated: User` field → nest `getUserQueryArgs` - The shared type has a `teams: Team[]` field that needs team names → nest with `select: { teamName: true, teamId: true }` **Bad reasons to nest:** + - "The frontend might need it eventually" — add it when it's actually needed - Nesting three or more levels deep without confirming the transformer uses all that data @@ -165,14 +162,10 @@ When nesting gets deep, consider whether a separate endpoint with its own query Many query args accept `organizationId` to scope nested relations. The most common case is filtering user roles to the current organization: ```typescript -export const getUserQueryArgs = ( - organizationId?: string -) => +export const getUserQueryArgs = (organizationId?: string) => Prisma.validator()({ select: { - roles: organizationId - ? { where: { organizationId } } - : true, + roles: organizationId ? { where: { organizationId } } : true, userId: true, firstName: true, lastName: true, @@ -188,12 +181,8 @@ Pass `organizationId` through from the service method. If your query args don't Query args MUST filter out soft-deleted records in nested relations using `where: { dateDeleted: null }`. This applies at every nesting level: ```typescript -export const getWorkPackageQueryArgs = ( - organizationId: string -) => - Prisma.validator< - Prisma.Work_PackageDefaultArgs - >()({ +export const getWorkPackageQueryArgs = (organizationId: string) => + Prisma.validator()({ include: { blockedBy: { where: { dateDeleted: null } @@ -206,9 +195,7 @@ export const getWorkPackageQueryArgs = ( include: { descriptionBullets: { where: { dateDeleted: null }, - ...getDescriptionBulletQueryArgs( - organizationId - ) + ...getDescriptionBulletQueryArgs(organizationId) }, changes: { where: { @@ -242,14 +229,10 @@ A transformer is a pure function that takes a Prisma result (typed using the que // src/backend/src/transformers/calendar.transformer.ts import { Prisma } from '@prisma/client'; import { Shop } from 'shared'; -import { ShopQueryArgs } - from '../prisma-query-args/shop.query-args.js'; -import { userTransformer } - from './user.transformer.js'; - -export const shopTransformer = ( - shop: Prisma.ShopGetPayload -): Shop => { +import { ShopQueryArgs } from '../prisma-query-args/shop.query-args.js'; +import { userTransformer } from './user.transformer.js'; + +export const shopTransformer = (shop: Prisma.ShopGetPayload): Shop => { return { shopId: shop.shopId, name: shop.name, @@ -267,18 +250,16 @@ export const shopTransformer = ( ### Common Transformer Operations **Renaming fields** — when Prisma column names differ from the shared type: + ```typescript color: calendar.colorHexCode, ``` **Mapping enums** — Prisma enums and shared enums are separate types. Create a mapping: + ```typescript -export const eventStatusTransformer = ( - status: PrismaEventStatus -): EventStatus => { - const mapping: Record< - PrismaEventStatus, EventStatus - > = { +export const eventStatusTransformer = (status: PrismaEventStatus): EventStatus => { + const mapping: Record = { UNCONFIRMED: EventStatus.UNCONFIRMED, CONFIRMED: EventStatus.CONFIRMED, SCHEDULED: EventStatus.SCHEDULED, @@ -289,12 +270,14 @@ export const eventStatusTransformer = ( ``` **Converting nulls to undefined** — Prisma uses `null` for optional fields, but shared types often use `undefined`: + ```typescript location: event.location ?? undefined, zoomLink: event.zoomLink ?? undefined, ``` **Transforming nested relations** — call other transformers for nested objects: + ```typescript requiredMembers: event.requiredMembers.map(userTransformer), @@ -306,8 +289,8 @@ teams: event.teams.map((team) => ({ })), ``` - **Computing derived fields** — some shared types have fields that don't exist in the database: + ```typescript endDate: calculateEndDate( wpInput.startDate, wpInput.duration @@ -320,11 +303,7 @@ deleted: wpInput.wbsElement.dateDeleted !== null, Transformers compose naturally. A `shopMachineryTransformer` calls `shopTransformer`, which calls `userTransformer`: ```typescript -export const shopMachineryTransformer = ( - sm: Prisma.Shop_MachineryGetPayload< - ShopMachineryQueryArgs - > -): ShopMachinery => { +export const shopMachineryTransformer = (sm: Prisma.Shop_MachineryGetPayload): ShopMachinery => { return { shopMachineryId: sm.shopMachineryId, shop: shopTransformer(sm.shop), @@ -342,19 +321,19 @@ When the frontend needs a lightweight version of an entity (for dropdowns, lists ```typescript // Query args: minimal select export const getWorkPackagePreviewQueryArgs = () => - Prisma.validator< - Prisma.Work_PackageDefaultArgs - >()({ - select: { /* only essential fields */ } + Prisma.validator()({ + select: { + /* only essential fields */ + } }); // Transformer: maps to preview type export const workPackagePreviewTransformer = ( - wp: Prisma.Work_PackageGetPayload< - WorkPackagePreviewQueryArgs - > + wp: Prisma.Work_PackageGetPayload ): WorkPackagePreview => { - return { /* minimal fields */ }; + return { + /* minimal fields */ + }; }; ``` diff --git a/docs-site/docs/general-practices/repository-overview.md b/docs-site/docs/general-practices/repository-overview.md index 424f4f0845..3aff6a3aea 100644 --- a/docs-site/docs/general-practices/repository-overview.md +++ b/docs-site/docs/general-practices/repository-overview.md @@ -52,6 +52,7 @@ src/backend/ ``` Key technology choices: + - **Express 5** for HTTP routing and middleware - **Prisma 6** as the ORM with PostgreSQL - **express-validator** for request input validation on routes @@ -82,6 +83,7 @@ src/frontend/ ``` Key technology choices: + - **React 19** with functional components and hooks - **Vite 6** for dev server and production builds - **Material-UI (MUI) v6** for the component library and styling @@ -123,6 +125,7 @@ src/shared/ ``` Types are imported throughout the codebase as: + ```typescript import { Project, User, WbsNumber } from 'shared'; ``` @@ -212,23 +215,23 @@ FinishLine uses an unconventional HTTP method pattern: **GET for reads, POST for When looking for code related to a specific feature, files follow a consistent naming pattern across the stack: -| Layer | Path Pattern | Example (Calendar) | -|-------|-------------|-------------------| -| Routes | `src/backend/src/routes/{feature}.routes.ts` | `calendar.routes.ts` | -| Controllers | `src/backend/src/controllers/{feature}.controllers.ts` | `calendar.controllers.ts` | -| Services | `src/backend/src/services/{feature}.services.ts` | `calendar.services.ts` | -| Prisma Query Args | `src/backend/src/prisma-query-args/{feature}.query-args.ts` | `calendar.query-args.ts` | -| Transformers | `src/backend/src/transformers/{feature}.transformer.ts` | `calendar.transformer.ts` | -| Backend Utils | `src/backend/src/utils/{feature}.utils.ts` | `calendar.utils.ts` | -| Backend Tests | `src/backend/tests/unit/{feature}.test.ts` | `calendar.test.ts` | -| Shared Types | `src/shared/src/types/{feature}-types.ts` | `calendar-types.ts` | -| Frontend APIs | `src/frontend/src/apis/{feature}.api.ts` | `calendar.api.ts` | -| Frontend Hooks | `src/frontend/src/hooks/{feature}.hooks.ts` | `calendar.hooks.ts` | -| Frontend Pages | `src/frontend/src/pages/{FeaturePage}/` | `CalendarPage/` | -| Frontend Utils | `src/frontend/src/utils/{feature}.utils.ts` | `calendar.utils.ts` | -| Frontend Tests | `src/frontend/src/tests/pages/{FeaturePage}/` | — | -| URL Builders | `src/frontend/src/utils/urls.ts` | (all in one file) | -| Frontend Routes | `src/frontend/src/utils/routes.ts` | (all in one file) | +| Layer | Path Pattern | Example (Calendar) | +| ----------------- | ----------------------------------------------------------- | ------------------------- | +| Routes | `src/backend/src/routes/{feature}.routes.ts` | `calendar.routes.ts` | +| Controllers | `src/backend/src/controllers/{feature}.controllers.ts` | `calendar.controllers.ts` | +| Services | `src/backend/src/services/{feature}.services.ts` | `calendar.services.ts` | +| Prisma Query Args | `src/backend/src/prisma-query-args/{feature}.query-args.ts` | `calendar.query-args.ts` | +| Transformers | `src/backend/src/transformers/{feature}.transformer.ts` | `calendar.transformer.ts` | +| Backend Utils | `src/backend/src/utils/{feature}.utils.ts` | `calendar.utils.ts` | +| Backend Tests | `src/backend/tests/unit/{feature}.test.ts` | `calendar.test.ts` | +| Shared Types | `src/shared/src/types/{feature}-types.ts` | `calendar-types.ts` | +| Frontend APIs | `src/frontend/src/apis/{feature}.api.ts` | `calendar.api.ts` | +| Frontend Hooks | `src/frontend/src/hooks/{feature}.hooks.ts` | `calendar.hooks.ts` | +| Frontend Pages | `src/frontend/src/pages/{FeaturePage}/` | `CalendarPage/` | +| Frontend Utils | `src/frontend/src/utils/{feature}.utils.ts` | `calendar.utils.ts` | +| Frontend Tests | `src/frontend/src/tests/pages/{FeaturePage}/` | — | +| URL Builders | `src/frontend/src/utils/urls.ts` | (all in one file) | +| Frontend Routes | `src/frontend/src/utils/routes.ts` | (all in one file) | ## Feature Areas @@ -258,6 +261,7 @@ FinishLine requires **Docker** for the PostgreSQL database regardless of how you ### Initial Setup First time setup (or after pulling new dependencies): + ```bash yarn install # Install all workspace dependencies yarn prisma:generate # Generate the Prisma client from the schema @@ -266,6 +270,7 @@ yarn prisma:generate # Generate the Prisma client from the schema ### Database Setup The PostgreSQL database always runs in a Docker container. The `yarn database:setup` command handles everything: it writes the `DATABASE_URL` to `src/backend/.env`, starts a PostgreSQL container named `finishline` on port 5432, creates the `nerpm` database, and runs Prisma migrations with seed data: + ```bash yarn database:setup # One-time: create Postgres container + seed DB ``` @@ -277,12 +282,14 @@ After initial setup, the container persists. If you restart your machine, start You have two options for running the frontend and backend: on your host machine or in Docker containers. Either way, they connect to the same PostgreSQL container. **Option A: Host machine (recommended for faster iteration)** + ```bash yarn start # Builds shared, starts backend (nodemon, port 3001) # + frontend (vite, port 3000) concurrently ``` Or run them individually: + ```bash yarn frontend # Frontend dev server on port 3000 yarn backend:dev # Backend with nodemon on port 3001 @@ -290,6 +297,7 @@ yarn workspace shared build # Rebuild shared (required after changing shared t ``` **Option B: Docker containers** + ```bash yarn docker:start # Start frontend + backend + DB containers yarn docker:dev # Full docker dev environment with watch mode @@ -299,6 +307,7 @@ yarn docker:i # Install deps inside containers ### Database Commands These commands manage the Prisma schema and database state: + ```bash yarn prisma:generate # Regenerate Prisma client — run after ANY schema.prisma change yarn prisma:migrate # Create and apply a new migration — run after adding/changing diff --git a/docs-site/docusaurus.config.js b/docs-site/docusaurus.config.js index 5e4a9cd5f8..7bdfcf258d 100644 --- a/docs-site/docusaurus.config.js +++ b/docs-site/docusaurus.config.js @@ -4,12 +4,12 @@ // There are various equivalent ways to declare your Docusaurus config. // See: https://docusaurus.io/docs/api/docusaurus-config -import {themes as prismThemes} from 'prism-react-renderer'; +import { themes as prismThemes } from 'prism-react-renderer'; /** @type {import('@docusaurus/types').Config} */ const config = { title: 'FinishLine Documentation', - tagline: 'Developer documentation for Northeastern Electric Racing\'s project management platform', + tagline: "Developer documentation for Northeastern Electric Racing's project management platform", favicon: 'img/favicon.ico', // Production URL - update this when deploying @@ -29,8 +29,8 @@ const config = { format: 'mdx', mermaid: false, hooks: { - onBrokenMarkdownLinks: 'warn', - }, + onBrokenMarkdownLinks: 'warn' + } }, // Even if you don't use internationalization, you can use this field to set @@ -38,7 +38,7 @@ const config = { // may want to replace "en" with "zh-Hans". i18n: { defaultLocale: 'en', - locales: ['en'], + locales: ['en'] }, presets: [ @@ -49,15 +49,14 @@ const config = { docs: { sidebarPath: './sidebars.js', // Point to the source documentation files in docs-site/docs/ - editUrl: - 'https://github.com/Northeastern-Electric-Racing/FinishLine/edit/main/docs-site/docs/', + editUrl: 'https://github.com/Northeastern-Electric-Racing/FinishLine/edit/main/docs-site/docs/' }, blog: false, theme: { - customCss: './src/css/custom.css', - }, - }), - ], + customCss: './src/css/custom.css' + } + }) + ] ], themeConfig: @@ -70,28 +69,28 @@ const config = { logo: { alt: 'NER Logo', src: 'img/logo.png', - href: '/docs/intro', + href: '/docs/intro' }, items: [ { type: 'docSidebar', sidebarId: 'tutorialSidebar', position: 'left', - label: 'Documentation', + label: 'Documentation' }, { href: 'https://github.com/Northeastern-Electric-Racing/FinishLine', label: 'GitHub', - position: 'right', - }, - ], + position: 'right' + } + ] }, prism: { theme: prismThemes.github, - darkTheme: prismThemes.dracula, - }, - }), + darkTheme: prismThemes.dracula + } + }) }; export default config; diff --git a/docs-site/scripts/generate-sidebar.js b/docs-site/scripts/generate-sidebar.js index d67fc5fee5..94ca8c0eb1 100644 --- a/docs-site/scripts/generate-sidebar.js +++ b/docs-site/scripts/generate-sidebar.js @@ -35,7 +35,7 @@ function buildSidebarStructure(dir, basePath = '') { items.push({ type: 'category', label: label, - items: categoryItems, + items: categoryItems }); } }); diff --git a/docs-site/scripts/sync-skills.js b/docs-site/scripts/sync-skills.js index 301315e46a..3d8a823a69 100644 --- a/docs-site/scripts/sync-skills.js +++ b/docs-site/scripts/sync-skills.js @@ -109,32 +109,32 @@ function transformLinksForSkills(content) { if (linkPath.endsWith('/SKILL.md')) { return fullMatch; } - + // Skip external links (http/https) if (linkPath.startsWith('http://') || linkPath.startsWith('https://')) { return fullMatch; } - + // Skip anchor links if (linkPath.startsWith('#')) { return fullMatch; } - + // Transform ./doc → ../doc/SKILL.md if (linkPath.startsWith('./')) { const cleanPath = linkPath.substring(2); // Remove ./ return `[${linkText}](../${cleanPath}/SKILL.md)`; } - + // Transform ../doc → ../../doc/SKILL.md if (linkPath.startsWith('../')) { return `[${linkText}](../${linkPath}/SKILL.md)`; } - + // Leave other links unchanged return fullMatch; }); - + return content; } From 927c3fa46e0d9484013d13875a66a31e11b96d78 Mon Sep 17 00:00:00 2001 From: Raphael Bessin Date: Tue, 24 Feb 2026 21:05:37 -0500 Subject: [PATCH 3/3] fixed link issues and updated docs to use ems when possible --- docs-site/{babel.config.js => babel.config.cjs} | 0 .../docs/general-practices/frontend-hooks-and-apis.md | 2 +- docs-site/docusaurus.config.js | 2 +- docs-site/package.json | 4 ++-- .../{generate-sidebar.js => generate-sidebar.mjs} | 9 +++++++-- docs-site/scripts/{sync-skills.js => sync-skills.mjs} | 9 +++++++-- 6 files changed, 18 insertions(+), 8 deletions(-) rename docs-site/{babel.config.js => babel.config.cjs} (100%) rename docs-site/scripts/{generate-sidebar.js => generate-sidebar.mjs} (92%) rename docs-site/scripts/{sync-skills.js => sync-skills.mjs} (96%) diff --git a/docs-site/babel.config.js b/docs-site/babel.config.cjs similarity index 100% rename from docs-site/babel.config.js rename to docs-site/babel.config.cjs diff --git a/docs-site/docs/general-practices/frontend-hooks-and-apis.md b/docs-site/docs/general-practices/frontend-hooks-and-apis.md index 8c34d5ffcb..4dc6921e9c 100644 --- a/docs-site/docs/general-practices/frontend-hooks-and-apis.md +++ b/docs-site/docs/general-practices/frontend-hooks-and-apis.md @@ -192,7 +192,7 @@ export const getAllEvents = () => { }; ``` -See the [query-args-and-transformers skill](../../general-practices/query-args-and-transformers/SKILL.md) for detailed transformer patterns. +See the [query-args-and-transformers](./query-args-and-transformers) for detailed transformer patterns. ### Step 4: Write the Query Hook diff --git a/docs-site/docusaurus.config.js b/docs-site/docusaurus.config.js index 7bdfcf258d..08cb9b84e4 100644 --- a/docs-site/docusaurus.config.js +++ b/docs-site/docusaurus.config.js @@ -49,7 +49,7 @@ const config = { docs: { sidebarPath: './sidebars.js', // Point to the source documentation files in docs-site/docs/ - editUrl: 'https://github.com/Northeastern-Electric-Racing/FinishLine/edit/main/docs-site/docs/' + editUrl: 'https://github.com/Northeastern-Electric-Racing/FinishLine/edit/main/docs-site/' }, blog: false, theme: { diff --git a/docs-site/package.json b/docs-site/package.json index 3192c0b650..66e45c35f2 100644 --- a/docs-site/package.json +++ b/docs-site/package.json @@ -12,8 +12,8 @@ "serve": "docusaurus serve", "write-translations": "docusaurus write-translations", "write-heading-ids": "docusaurus write-heading-ids", - "sync-skills": "node scripts/sync-skills.js", - "generate-sidebar": "node scripts/generate-sidebar.js", + "sync-skills": "node scripts/sync-skills.mjs", + "generate-sidebar": "node scripts/generate-sidebar.mjs", "docs:dev": "yarn generate-sidebar && yarn start", "docs:build": "yarn generate-sidebar && yarn build" }, diff --git a/docs-site/scripts/generate-sidebar.js b/docs-site/scripts/generate-sidebar.mjs similarity index 92% rename from docs-site/scripts/generate-sidebar.js rename to docs-site/scripts/generate-sidebar.mjs index 94ca8c0eb1..e0ed7d1747 100644 --- a/docs-site/scripts/generate-sidebar.js +++ b/docs-site/scripts/generate-sidebar.mjs @@ -1,5 +1,10 @@ -const fs = require('fs'); -const path = require('path'); +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +// ESM equivalent of __dirname +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); // Paths const DOCS_DIR = path.join(__dirname, '../docs'); diff --git a/docs-site/scripts/sync-skills.js b/docs-site/scripts/sync-skills.mjs similarity index 96% rename from docs-site/scripts/sync-skills.js rename to docs-site/scripts/sync-skills.mjs index 3d8a823a69..b78b8aefb8 100644 --- a/docs-site/scripts/sync-skills.js +++ b/docs-site/scripts/sync-skills.mjs @@ -1,5 +1,10 @@ -const fs = require('fs'); -const path = require('path'); +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +// ESM equivalent of __dirname +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); // Paths const DOCS_DIR = path.join(__dirname, '../docs');