From 624bea59e79192a50ba2698f212f1e9d9b4d4dfe Mon Sep 17 00:00:00 2001 From: cjmot <146262493+cjmot@users.noreply.github.com> Date: Mon, 12 Jan 2026 14:17:22 -0700 Subject: [PATCH 01/42] added .idea (webstorm generated codespace files) to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 385d21505..2feea99ac 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ config.js coverage dist **/.vite +.idea \ No newline at end of file From 360f509bc9e750d9ed6e2a30aedf33f80c4b854a Mon Sep 17 00:00:00 2001 From: cjmot <146262493+cjmot@users.noreply.github.com> Date: Tue, 13 Jan 2026 20:04:05 -0700 Subject: [PATCH 02/42] Fill in notes.md for first deliverable --- notes.md | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/notes.md b/notes.md index df8a5a7bd..06b2e814c 100644 --- a/notes.md +++ b/notes.md @@ -4,23 +4,23 @@ As part of `Deliverable ⓵ Development deployment: JWT Pizza`, start up the application and debug through the code until you understand how it works. During the learning process fill out the following required pieces of information in order to demonstrate that you have successfully completed the deliverable. -| User activity | Frontend component | Backend endpoints | Database SQL | -| --------------------------------------------------- | ------------------ | ----------------- | ------------ | -| View home page | | | | -| Register new user
(t@jwt.com, pw: test) | | | | -| Login new user
(t@jwt.com, pw: test) | | | | -| Order pizza | | | | -| Verify pizza | | | | -| View profile page | | | | -| View franchise
(as diner) | | | | -| Logout | | | | -| View About page | | | | -| View History page | | | | -| Login as franchisee
(f@jwt.com, pw: franchisee) | | | | -| View franchise
(as franchisee) | | | | -| Create a store | | | | -| Close a store | | | | -| Login as admin
(a@jwt.com, pw: admin) | | | | -| View Admin page | | | | -| Create a franchise for t@jwt.com | | | | -| Close the franchise for t@jwt.com | | | | +| User activity | Frontend component | Backend endpoints | Database SQL | +|-----------------------------------------------------|------------------------|------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| View home page | home.tsx | none | none | +| Register new user
(t@jwt.com, pw: test) | register.tsx | [POST]/api/auth | ```INSERT INTO user (name, email, password) VALUES (?, ?, ?)```
```INSERT INTO userRole (userId, role, objectId) VALUES (?, ?, ?)``` | +| Login new user
(t@jwt.com, pw: test) | login.tsx | [PUT]/api/auth | ```SELECT * FROM user WHERE email=?```
```SELECT * FROM userRole WHERE userId=?```
```INSERT INTO auth (token, userId) VALUES (?, ?) ON DUPLICATE KEY UPDATE token=token``` | +| Order pizza | menu.tsx, payment.tsx | [GET]/api/order/menu
[GET]/api/franchise?page=\${page}&limit\${limit}&name=${nameFilter} | ```SELECT * FROM menu```
```SELECT id, name FROM franchise WHERE name LIKE ? LIMIT ${limit + 1} OFFSET ${offset}```
```SELECT id, name FROM store WHERE franchiseId=?```
```INSERT INTO dinerOrder (dinerId, franchiseId, storeId, date) VALUES (?, ?, ?, now())```
```INSERT INTO orderItem (orderId, menuId, description, price) VALUES (?, ?, ?, ?)``` | +| Verify pizza | delivery.tsx | [POST]api/order/verify | none | +| View profile page | dinerDashboard.tsx | [GET]/api/orders | ```SELECT id, franchiseId, storeId, date FROM dinerOrder WHERE dinerId=? LIMIT ${offset},${config.db.listPerPage}``` | +| View franchise
(as diner) | franchiseDashboard.tsx | [GET]/api/franchise/${user.id} | ```SELECT objectId FROM userRole WHERE role='franchisee' AND userId=?``` | +| Logout | logout.tsx | [DELETE]/api/auth | ```DELETE FROM auth WHERE token=?``` | +| View About page | about.tsx | none | none | +| View History page | history.tsx | none | none | +| Login as franchisee
(f@jwt.com, pw: franchisee) | login.tsx | [POST]/api/auth | ```SELECT * FROM user WHERE email=?```
```SELECT * FROM userRole WHERE userId=?```
```INSERT INTO auth (token, userId) VALUES (?, ?) ON DUPLICATE KEY UPDATE token=token``` | +| View franchise
(as franchisee) | franchiseDashboard.tsx | [GET]/api/franchise/${user.id} | ```SELECT u.id, u.name, u.email FROM userRole AS ur JOIN user AS u ON u.id=ur.userId WHERE ur.objectId=? AND ur.role='franchisee'```
```SELECT s.id, s.name, COALESCE(SUM(oi.price), 0) AS totalRevenue FROM dinerOrder AS do JOIN orderItem AS oi ON do.id=oi.orderId RIGHT JOIN store AS s ON s.id=do.storeId WHERE s.franchiseId=? GROUP BY s.id``` | +| Create a store | createStore.tsx | [POST]/api/franchise/1/store | ```INSERT INTO store (franchiseId, name) VALUES (?, ?)``` | +| Close a store | closeStore.tsx | [DELETE]/api/franchise/\${franchise.id}/store/${store.id} | ```DELETE FROM store WHERE franchiseId=? AND id=?``` | +| Login as admin
(a@jwt.com, pw: admin) | login.tsx | [PUT]/api/auth | ```SELECT * FROM user WHERE email=?```
```SELECT * FROM userRole WHERE userId=?```
```INSERT INTO auth (token, userId) VALUES (?, ?) ON DUPLICATE KEY UPDATE token=token``` | +| View Admin page | adminDashboard.tsx | [GET]/api/franchise?page=\${page}&limit=\${limit}&name=${nameFilter} | ```SELECT id, name FROM franchise WHERE name LIKE ? LIMIT ${limit + 1} OFFSET ${offset}```
```SELECT u.id, u.name, u.email FROM userRole AS ur JOIN user AS u ON u.id=ur.userId WHERE ur.objectId=? AND ur.role='franchisee'```
```SELECT s.id, s.name, COALESCE(SUM(oi.price), 0) AS totalRevenue FROM dinerOrder AS do JOIN orderItem AS oi ON do.id=oi.orderId RIGHT JOIN store AS s ON s.id=do.storeId WHERE s.franchiseId=? GROUP BY s.id``` | +| Create a franchise for t@jwt.com | createFranchise.tsx | [POST]/api/franchise/${user.id} | ```SELECT id, name FROM user WHERE email=?```
```INSERT INTO franchise (name) VALUES (?)```
```INSERT INTO userRole (userId, role, objectId) VALUES (?, ?, ?)``` | +| Close the franchise for t@jwt.com | closeFranchise.tsx | [DELETE]/api/franchise/${franchise.id} | ```DELETE FROM store WHERE franchiseId=?```
```DELETE FROM userRole WHERE objectId=?```
```DELETE FROM franchise WHERE id=?``` | From 96282eef2c0226cd7658f7941e403b212254b876 Mon Sep 17 00:00:00 2001 From: Cooper Motyer <146262493+cjmot@users.noreply.github.com> Date: Wed, 14 Jan 2026 13:42:56 -0700 Subject: [PATCH 03/42] Create test.yml --- .github/workflows/test.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 000000000..1cfdb774d --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,11 @@ +name: basic + +on: + workflow_dispatch: + +jobs: + greeter: + runs-on: ubuntu-latest + steps: + - run: echo hello + - run: echo goodbye From baec78be5b2d4c7c0527fe76d5d250da13ab0c17 Mon Sep 17 00:00:00 2001 From: Cooper Motyer <146262493+cjmot@users.noreply.github.com> Date: Wed, 14 Jan 2026 13:48:57 -0700 Subject: [PATCH 04/42] Add CI Pipeline file --- .github/workflows/ci.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..89ea0a09b --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,11 @@ +name: CI Pipeline + +on: + push: + branches: + - main +jobs: + test: + runs-on: ubuntu-latest + steps: + - run: echo "Hello GitHub Actions" From 2f8581ca56c3d6798eab70c4e95afa8f60483ace Mon Sep 17 00:00:00 2001 From: Cooper Motyer <146262493+cjmot@users.noreply.github.com> Date: Wed, 14 Jan 2026 13:59:54 -0700 Subject: [PATCH 05/42] Update ci.yml for github pages exercise --- .github/workflows/ci.yml | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 89ea0a09b..dfff07651 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,8 +4,31 @@ on: push: branches: - main + workflow_dispatch: jobs: - test: + build: + name: Build runs-on: ubuntu-latest steps: - - run: echo "Hello GitHub Actions" + - name: create static deployment file + run: | + mkdir dist + echo "

Hello GitHub Pages

" >> dist/index.html + + - name: Update pages artifact + uses: actions/upload-pages-artifact@v3 + with: + path: dist/ + deploy: + needs: build + permissions: + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 From ed43ed692db62f1d0859bcea552bf121f51c61d7 Mon Sep 17 00:00:00 2001 From: Cooper Motyer <146262493+cjmot@users.noreply.github.com> Date: Thu, 15 Jan 2026 15:53:25 -0700 Subject: [PATCH 06/42] Update ci pipeline to deploy jwt-pizza --- .github/workflows/ci.yml | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dfff07651..624dcb090 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,11 +9,28 @@ jobs: build: name: Build runs-on: ubuntu-latest + outputs: + version: ${{ steps.set_version.outputs.version }} steps: - - name: create static deployment file + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: '22.x' + + - name: set version + id: set_version + run: | + version=$(date +'%Y%m%d.%H%M%S') + echo "version=$version" >> "$GITHUB_OUTPUT" + printf '{"version": "%s" }' "$version" > public/version.json + + - name: Build run: | - mkdir dist - echo "

Hello GitHub Pages

" >> dist/index.html + npm ci && npm run build + cp dist/index.html dist/404.html - name: Update pages artifact uses: actions/upload-pages-artifact@v3 From 7359406843e5bbb6999fbdc0e31d2300c99a366b Mon Sep 17 00:00:00 2001 From: Cooper Motyer <146262493+cjmot@users.noreply.github.com> Date: Thu, 15 Jan 2026 16:35:24 -0700 Subject: [PATCH 07/42] Add CI pipeline badge to README --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 560298b7a..804d34098 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # 🍕 JWT Pizza -![Coverage badge](https://pizza-factory.cs329.click/api/badge/accountId/jwtpizzacoverage?t=1) +![Coverage badge](https://pizza-factory.cs329.click/api/badge/accountId/jwtpizzacoverage?t=1)
+[![CI Pipeline](https://github.com/cjmot/jwt-pizza/actions/workflows/ci.yml/badge.svg?branch=main&event=deployment_status)](https://github.com/cjmot/jwt-pizza/actions/workflows/ci.yml) A JSON Web Token, or [JWT](https://jwt.io/introduction), (pronounced JOT) is a digitally signed transfer of information using JSON notation. Because you can validate the digital signature you can buy JWT pizzas with confidence. From d5c6d7dad979b04267414ae55987727db42ca5eb Mon Sep 17 00:00:00 2001 From: Cooper Motyer <146262493+cjmot@users.noreply.github.com> Date: Fri, 16 Jan 2026 11:21:54 -0700 Subject: [PATCH 08/42] Update CI Pipeline badge in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 804d34098..eaa7b9ed9 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # 🍕 JWT Pizza ![Coverage badge](https://pizza-factory.cs329.click/api/badge/accountId/jwtpizzacoverage?t=1)
-[![CI Pipeline](https://github.com/cjmot/jwt-pizza/actions/workflows/ci.yml/badge.svg?branch=main&event=deployment_status)](https://github.com/cjmot/jwt-pizza/actions/workflows/ci.yml) +[![CI Pipeline](https://github.com/cjmot/jwt-pizza/actions/workflows/ci.yml/badge.svg)](https://github.com/cjmot/jwt-pizza/actions/workflows/ci.yml) A JSON Web Token, or [JWT](https://jwt.io/introduction), (pronounced JOT) is a digitally signed transfer of information using JSON notation. Because you can validate the digital signature you can buy JWT pizzas with confidence. From 6963d3a5282867fd39759150f318e6bad751ec30 Mon Sep 17 00:00:00 2001 From: cjmot <146262493+cjmot@users.noreply.github.com> Date: Tue, 3 Feb 2026 16:34:00 -0700 Subject: [PATCH 09/42] Playwright install --- .env.development | 6 +- .gitignore | 11 +- .nycrc.json | 7 + package-lock.json | 2943 +++++++++++++++++++++++++++++++++++------- package.json | 11 +- playwright.config.ts | 31 + tests/auth.spec.ts | 5 + vite.config.ts | 13 + 8 files changed, 2565 insertions(+), 462 deletions(-) create mode 100644 .nycrc.json create mode 100644 playwright.config.ts create mode 100644 tests/auth.spec.ts create mode 100644 vite.config.ts diff --git a/.env.development b/.env.development index eb9dd3935..8595b4211 100644 --- a/.env.development +++ b/.env.development @@ -1,2 +1,4 @@ -VITE_PIZZA_SERVICE_URL=http://localhost:3000 -VITE_PIZZA_FACTORY_URL=https://pizza-factory.cs329.click \ No newline at end of file +VITE_PIZZA_SERVICE_URL=https://pizza-service.cs329.click +VITE_PIZZA_FACTORY_URL=https://pizza-factory.cs329.click + +# TODO: Update service variable to run tests \ No newline at end of file diff --git a/.gitignore b/.gitignore index 2feea99ac..cd2570cfb 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,13 @@ config.js coverage dist **/.vite -.idea \ No newline at end of file +.idea + +# Playwright +node_modules/ +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ +/playwright/.auth/ +.nyc_output \ No newline at end of file diff --git a/.nycrc.json b/.nycrc.json new file mode 100644 index 000000000..57da1dfb9 --- /dev/null +++ b/.nycrc.json @@ -0,0 +1,7 @@ +{ + "check-coverage": true, + "branches": 100, + "lines": 100, + "functions": 100, + "statements": 100 +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 586c558e7..3106f961a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,16 +12,21 @@ "preline": "^2.1.0", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-router-dom": "^6.22.3" + "react-router-dom": "^6.22.3", + "vite-plugin-istanbul": "^7.2.1" }, "devDependencies": { + "@playwright/test": "^1.58.1", + "@types/node": "^25.2.0", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", "autoprefixer": "^10.4.19", + "nyc": "^17.1.0", + "playwright-test-coverage": "^1.2.12", "postcss": "^8.4.38", "tailwindcss": "^3.4.3", "typescript": "^5.5.4", - "vite": "^5.2.8" + "vite": "7.1.11" } }, "node_modules/@alloc/quick-lru": { @@ -36,379 +41,679 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "license": "MIT", + "peer": true, + "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" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz", + "integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==", + "license": "MIT", + "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" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "license": "MIT", + "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" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", - "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", "cpu": [ "ppc64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "aix" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", - "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", "cpu": [ "arm" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", - "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", "cpu": [ "arm64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", - "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", "cpu": [ "x64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", - "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", "cpu": [ "arm64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", - "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", "cpu": [ "x64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", - "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", "cpu": [ "arm64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", - "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", "cpu": [ "x64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", - "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", "cpu": [ "arm" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", - "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", "cpu": [ "arm64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", - "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", "cpu": [ "ia32" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", - "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", "cpu": [ "loong64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", - "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", "cpu": [ "mips64el" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", - "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", "cpu": [ "ppc64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", - "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", "cpu": [ "riscv64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", - "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", "cpu": [ "s390x" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", - "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", "cpu": [ "x64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", - "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", "cpu": [ "x64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "netbsd" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", - "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", "cpu": [ "x64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "openbsd" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", - "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", "cpu": [ "x64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "sunos" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", - "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", "cpu": [ "arm64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", - "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", "cpu": [ "ia32" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", - "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", "cpu": [ "x64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, + "license": "ISC", "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -421,49 +726,70 @@ "node": ">=12" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "license": "ISC", "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" } }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -508,12 +834,29 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, + "license": "MIT", "optional": true, "engines": { "node": ">=14" } }, + "node_modules/@playwright/test": { + "version": "1.58.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.58.1.tgz", + "integrity": "sha512-6LdVIUERWxQMmUSSQi0I53GgCBYgM2RpGngCPY7hSeju+VrKjq3lvs7HpJoPbDiY5QM5EYRtRX5fvrinnMAz3w==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "playwright": "1.58.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@popperjs/core": { "version": "2.11.8", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", @@ -532,205 +875,355 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.14.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.14.1.tgz", - "integrity": "sha512-fH8/o8nSUek8ceQnT7K4EQbSiV7jgkHq81m9lWZFIXjJ7lJzpWXbQFpT/Zh6OZYnpFykvzC3fbEvEAFZu03dPA==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz", + "integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==", "cpu": [ "arm" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.14.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.14.1.tgz", - "integrity": "sha512-Y/9OHLjzkunF+KGEoJr3heiD5X9OLa8sbT1lm0NYeKyaM3oMhhQFvPB0bNZYJwlq93j8Z6wSxh9+cyKQaxS7PQ==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz", + "integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==", "cpu": [ "arm64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.14.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.14.1.tgz", - "integrity": "sha512-+kecg3FY84WadgcuSVm6llrABOdQAEbNdnpi5X3UwWiFVhZIZvKgGrF7kmLguvxHNQy+UuRV66cLVl3S+Rkt+Q==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz", + "integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==", "cpu": [ "arm64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.14.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.14.1.tgz", - "integrity": "sha512-2pYRzEjVqq2TB/UNv47BV/8vQiXkFGVmPFwJb+1E0IFFZbIX8/jo1olxqqMbo6xCXf8kabANhp5bzCij2tFLUA==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz", + "integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==", "cpu": [ "x64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.14.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.14.1.tgz", - "integrity": "sha512-mS6wQ6Do6/wmrF9aTFVpIJ3/IDXhg1EZcQFYHZLHqw6AzMBjTHWnCG35HxSqUNphh0EHqSM6wRTT8HsL1C0x5g==", + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz", + "integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==", "cpu": [ - "arm" + "arm64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ - "linux" + "freebsd" ] }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.14.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.14.1.tgz", - "integrity": "sha512-p9rGKYkHdFMzhckOTFubfxgyIO1vw//7IIjBBRVzyZebWlzRLeNhqxuSaZ7kCEKVkm/kuC9fVRW9HkC/zNRG2w==", + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz", + "integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==", "cpu": [ - "arm64" + "x64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ - "linux" + "freebsd" ] }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.14.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.14.1.tgz", - "integrity": "sha512-nDY6Yz5xS/Y4M2i9JLQd3Rofh5OR8Bn8qe3Mv/qCVpHFlwtZSBYSPaU4mrGazWkXrdQ98GB//H0BirGR/SKFSw==", + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz", + "integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==", "cpu": [ - "arm64" + "arm" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.14.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.14.1.tgz", - "integrity": "sha512-im7HE4VBL+aDswvcmfx88Mp1soqL9OBsdDBU8NqDEYtkri0qV0THhQsvZtZeNNlLeCUQ16PZyv7cqutjDF35qw==", + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz", + "integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==", "cpu": [ - "ppc64le" + "arm" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.14.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.14.1.tgz", - "integrity": "sha512-RWdiHuAxWmzPJgaHJdpvUUlDz8sdQz4P2uv367T2JocdDa98iRw2UjIJ4QxSyt077mXZT2X6pKfT2iYtVEvOFw==", + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz", + "integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==", "cpu": [ - "riscv64" + "arm64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.14.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.14.1.tgz", - "integrity": "sha512-VMgaGQ5zRX6ZqV/fas65/sUGc9cPmsntq2FiGmayW9KMNfWVG/j0BAqImvU4KTeOOgYSf1F+k6at1UfNONuNjA==", + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz", + "integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==", "cpu": [ - "s390x" + "arm64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.14.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.14.1.tgz", - "integrity": "sha512-9Q7DGjZN+hTdJomaQ3Iub4m6VPu1r94bmK2z3UeWP3dGUecRC54tmVu9vKHTm1bOt3ASoYtEz6JSRLFzrysKlA==", + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz", + "integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==", "cpu": [ - "x64" + "loong64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.14.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.14.1.tgz", - "integrity": "sha512-JNEG/Ti55413SsreTguSx0LOVKX902OfXIKVg+TCXO6Gjans/k9O6ww9q3oLGjNDaTLxM+IHFMeXy/0RXL5R/g==", + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz", + "integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==", "cpu": [ - "x64" + "loong64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.14.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.14.1.tgz", - "integrity": "sha512-ryS22I9y0mumlLNwDFYZRDFLwWh3aKaC72CWjFcFvxK0U6v/mOkM5Up1bTbCRAhv3kEIwW2ajROegCIQViUCeA==", + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz", + "integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==", "cpu": [ - "arm64" + "ppc64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ - "win32" + "linux" ] }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.14.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.14.1.tgz", - "integrity": "sha512-TdloItiGk+T0mTxKx7Hp279xy30LspMso+GzQvV2maYePMAWdmrzqSNZhUpPj3CGw12aGj57I026PgLCTu8CGg==", + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz", + "integrity": "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==", "cpu": [ - "ia32" + "ppc64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ - "win32" + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz", + "integrity": "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz", + "integrity": "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz", + "integrity": "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz", + "integrity": "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz", + "integrity": "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz", + "integrity": "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz", + "integrity": "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz", + "integrity": "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz", + "integrity": "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz", + "integrity": "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.14.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.14.1.tgz", - "integrity": "sha512-wQGI+LY/Py20zdUPq+XCem7JcPOyzIJBm3dli+56DJsQOHbnXZFEwgmnC6el1TPAfC8lBT3m+z69RmLykNUbew==", + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz", + "integrity": "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==", "cpu": [ "x64" ], - "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ] }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.2.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.0.tgz", + "integrity": "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w==", + "devOptional": true, + "license": "MIT", + "peer": true, + "dependencies": { + "undici-types": "~7.16.0" + } }, "node_modules/@types/prop-types": { "version": "15.7.12", @@ -757,11 +1250,47 @@ "@types/react": "*" } }, - "node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "license": "MIT", + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", "dev": true, + "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", "engines": { "node": ">=12" }, @@ -770,10 +1299,10 @@ } }, "node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "license": "MIT", "engines": { "node": ">=12" }, @@ -800,12 +1329,41 @@ "node": ">= 8" } }, + "node_modules/append-transform": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", + "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-require-extensions": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", + "dev": true, + "license": "MIT" + }, "node_modules/arg": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", "dev": true }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, "node_modules/autoprefixer": { "version": "10.4.19", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz", @@ -846,8 +1404,16 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.9.19", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz", + "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } }, "node_modules/binary-extensions": { "version": "2.3.0", @@ -865,7 +1431,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -883,10 +1448,9 @@ } }, "node_modules/browserslist": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", - "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", - "dev": true, + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", "funding": [ { "type": "opencollective", @@ -901,11 +1465,14 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", + "peer": true, "dependencies": { - "caniuse-lite": "^1.0.30001587", - "electron-to-chromium": "^1.4.668", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.13" + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" @@ -914,6 +1481,31 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/caching-transform": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", + "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasha": "^5.0.0", + "make-dir": "^3.0.0", + "package-hash": "^4.0.0", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/camelcase-css": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", @@ -924,10 +1516,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001609", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001609.tgz", - "integrity": "sha512-JFPQs34lHKx1B5t1EpQpWH4c+29zIyn/haGsbpfq3suuV9v56enjFt23zqijxGTMwy1p/4H2tjnQMY+p1WoAyA==", - "dev": true, + "version": "1.0.30001767", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001767.tgz", + "integrity": "sha512-34+zUAMhSH+r+9eKmYG+k2Rpt8XttfE4yXAjoZvkAPs15xcYQhyBYdalJ65BzivAvGRMViEjy6oKr/S91loekQ==", "funding": [ { "type": "opencollective", @@ -941,7 +1532,8 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/chokidar": { "version": "3.6.0", @@ -979,11 +1571,109 @@ "node": ">= 6" } }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -995,7 +1685,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "license": "MIT" }, "node_modules/commander": { "version": "4.1.1", @@ -1006,11 +1696,31 @@ "node": ">= 6" } }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -1038,6 +1748,49 @@ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", "dev": true }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-require-extensions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.1.tgz", + "integrity": "sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "strip-bom": "^4.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -1054,67 +1807,119 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true + "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.4.735", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.735.tgz", - "integrity": "sha512-pkYpvwg8VyOTQAeBqZ7jsmpCjko1Qc6We1ZtZCjRyYbT5v4AIUKDy5cQTRotQlSSZmMr8jqpEt6JtOj5k7lR7A==", - "dev": true + "version": "1.5.286", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz", + "integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==", + "license": "ISC" }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true + "license": "MIT" }, - "node_modules/esbuild": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", - "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "node_modules/es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", "dev": true, + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", "hasInstallScript": true, + "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.20.2", - "@esbuild/android-arm": "0.20.2", - "@esbuild/android-arm64": "0.20.2", - "@esbuild/android-x64": "0.20.2", - "@esbuild/darwin-arm64": "0.20.2", - "@esbuild/darwin-x64": "0.20.2", - "@esbuild/freebsd-arm64": "0.20.2", - "@esbuild/freebsd-x64": "0.20.2", - "@esbuild/linux-arm": "0.20.2", - "@esbuild/linux-arm64": "0.20.2", - "@esbuild/linux-ia32": "0.20.2", - "@esbuild/linux-loong64": "0.20.2", - "@esbuild/linux-mips64el": "0.20.2", - "@esbuild/linux-ppc64": "0.20.2", - "@esbuild/linux-riscv64": "0.20.2", - "@esbuild/linux-s390x": "0.20.2", - "@esbuild/linux-x64": "0.20.2", - "@esbuild/netbsd-x64": "0.20.2", - "@esbuild/openbsd-x64": "0.20.2", - "@esbuild/sunos-x64": "0.20.2", - "@esbuild/win32-arm64": "0.20.2", - "@esbuild/win32-ia32": "0.20.2", - "@esbuild/win32-x64": "0.20.2" + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" } }, "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", - "dev": true, + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", "engines": { "node": ">=6" } }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", @@ -1164,13 +1969,44 @@ "node": ">=8" } }, - "node_modules/foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", "dev": true, + "license": "MIT", "dependencies": { - "cross-spawn": "^7.0.0", + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" }, "engines": { @@ -1193,11 +2029,38 @@ "url": "https://github.com/sponsors/rawify" } }, + "node_modules/fromentries": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", + "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, "hasInstallScript": true, "optional": true, "os": [ @@ -1216,24 +2079,51 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/glob": { - "version": "10.3.12", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", - "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.6", - "minimatch": "^9.0.1", - "minipass": "^7.0.4", - "path-scurry": "^1.10.2" + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, "funding": { "url": "https://github.com/sponsors/isaacs" } @@ -1250,6 +2140,40 @@ "node": ">=10.13.0" } }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hasha": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", + "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-stream": "^2.0.0", + "type-fest": "^0.8.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -1262,6 +2186,52 @@ "node": ">= 0.4" } }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -1299,7 +2269,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1325,22 +2295,175 @@ "node": ">=0.12.0" } }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "license": "ISC" }, - "node_modules/jackspeak": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", - "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-hook": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", + "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "@isaacs/cliui": "^8.0.2" + "append-transform": "^2.0.0" }, "engines": { - "node": ">=14" + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-processinfo": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.3.tgz", + "integrity": "sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==", + "dev": true, + "license": "ISC", + "dependencies": { + "archy": "^1.0.0", + "cross-spawn": "^7.0.3", + "istanbul-lib-coverage": "^3.2.0", + "p-map": "^3.0.0", + "rimraf": "^3.0.0", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report/node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -1353,16 +2476,53 @@ "version": "1.21.0", "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", - "dev": true, + "devOptional": true, "bin": { "jiti": "bin/jiti.js" } }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/lilconfig": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", @@ -1378,6 +2538,25 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", + "dev": true, + "license": "MIT" + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -1390,12 +2569,35 @@ } }, "node_modules/lru-cache": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", - "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, "engines": { - "node": "14 || >=16.14" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, "node_modules/merge2": { @@ -1424,7 +2626,6 @@ "version": "9.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -1436,14 +2637,20 @@ } }, "node_modules/minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", - "dev": true, + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" } }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, "node_modules/mz": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", @@ -1456,16 +2663,16 @@ } }, "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "dev": true, + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "funding": [ { "type": "github", "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -1473,11 +2680,24 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/node-preload": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", + "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "process-on-spawn": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", - "dev": true + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "license": "MIT" }, "node_modules/normalize-path": { "version": "3.0.0", @@ -1497,6 +2717,123 @@ "node": ">=0.10.0" } }, + "node_modules/nyc": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-17.1.0.tgz", + "integrity": "sha512-U42vQ4czpKa0QdI1hu950XuNhYqgoM+ZF1HT+VuUHL9hPfDPVvNQyltmMqdE9bUHMVa+8yNbc3QKTj8zQhlVxQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "caching-transform": "^4.0.0", + "convert-source-map": "^1.7.0", + "decamelize": "^1.2.0", + "find-cache-dir": "^3.2.0", + "find-up": "^4.1.0", + "foreground-child": "^3.3.0", + "get-package-type": "^0.1.0", + "glob": "^7.1.6", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-hook": "^3.0.0", + "istanbul-lib-instrument": "^6.0.2", + "istanbul-lib-processinfo": "^2.0.2", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "make-dir": "^3.0.0", + "node-preload": "^0.2.1", + "p-map": "^3.0.0", + "process-on-spawn": "^1.0.0", + "resolve-from": "^5.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "spawn-wrap": "^2.0.0", + "test-exclude": "^6.0.0", + "yargs": "^15.0.2" + }, + "bin": { + "nyc": "bin/nyc.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/nyc/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/nyc/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/nyc/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/nyc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/nyc/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/nyc/node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -1515,11 +2852,111 @@ "node": ">= 6" } }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-hash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", + "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "graceful-fs": "^4.1.15", + "hasha": "^5.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "license": "BlueOak-1.0.0" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1531,26 +2968,26 @@ "dev": true }, "node_modules/path-scurry": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", - "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", - "dev": true, + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=16 || 14 >=14.18" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", @@ -1582,11 +3019,80 @@ "node": ">= 6" } }, - "node_modules/postcss": { - "version": "8.4.38", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", - "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/playwright": { + "version": "1.58.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.1.tgz", + "integrity": "sha512-+2uTZHxSCcxjvGc5C891LrS1/NlxglGxzrC4seZiVjcYVQfUa87wBL6rTDqzGjuoWNjnBzRqKmF6zRYGMvQUaQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.58.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.58.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.1.tgz", + "integrity": "sha512-bcWzOaTxcW+VOOGBCQgnaKToLJ65d6AqfLVKEWvexyS3AS6rbXl+xdpYRMGSRBClPvyj44njOWoxjNdL/H9UNg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/playwright-test-coverage": { + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/playwright-test-coverage/-/playwright-test-coverage-1.2.12.tgz", + "integrity": "sha512-WdR3shV+7IWtlB1AZcXSysUyZmyAqXM9+DT3iBSS1p4SkJoWZslkTqk04l5ZExSkuaM+5fKl0M9TyUuJWuGgLA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@playwright/test": "^1.14.1" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", "funding": [ { "type": "opencollective", @@ -1601,10 +3107,12 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", + "peer": true, "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.2.0" + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" @@ -1739,6 +3247,19 @@ "@popperjs/core": "^2.11.2" } }, + "node_modules/process-on-spawn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.1.0.tgz", + "integrity": "sha512-JOnOPQ/8TZgjs1JIH/m9ni7FfimjNa/PRx7y/Wb5qdItsnhO0jE4AT7fC0HjC28DUQWDr50dwSYZLdRMlqDq3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "fromentries": "^1.2.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -1763,6 +3284,7 @@ "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -1774,6 +3296,7 @@ "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.0" @@ -1827,46 +3350,148 @@ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/release-zalgo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", + "integrity": "sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==", + "dev": true, + "license": "ISC", + "dependencies": { + "es6-error": "^4.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true, + "license": "ISC" + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, + "license": "ISC", "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" }, - "bin": { - "resolve": "bin/resolve" + "engines": { + "node": "*" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" + "node": "*" } }, "node_modules/rollup": { - "version": "4.14.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.14.1.tgz", - "integrity": "sha512-4LnHSdd3QK2pa1J6dFbfm1HN0D7vSK/ZuZTsdyUAlA6Rr1yTouUTL13HaDOGJVgby461AhrNGBS7sCGXXtT+SA==", - "dev": true, + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", + "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", + "license": "MIT", "dependencies": { - "@types/estree": "1.0.5" + "@types/estree": "1.0.8" }, "bin": { "rollup": "dist/bin/rollup" @@ -1876,21 +3501,31 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.14.1", - "@rollup/rollup-android-arm64": "4.14.1", - "@rollup/rollup-darwin-arm64": "4.14.1", - "@rollup/rollup-darwin-x64": "4.14.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.14.1", - "@rollup/rollup-linux-arm64-gnu": "4.14.1", - "@rollup/rollup-linux-arm64-musl": "4.14.1", - "@rollup/rollup-linux-powerpc64le-gnu": "4.14.1", - "@rollup/rollup-linux-riscv64-gnu": "4.14.1", - "@rollup/rollup-linux-s390x-gnu": "4.14.1", - "@rollup/rollup-linux-x64-gnu": "4.14.1", - "@rollup/rollup-linux-x64-musl": "4.14.1", - "@rollup/rollup-win32-arm64-msvc": "4.14.1", - "@rollup/rollup-win32-ia32-msvc": "4.14.1", - "@rollup/rollup-win32-x64-msvc": "4.14.1", + "@rollup/rollup-android-arm-eabi": "4.57.1", + "@rollup/rollup-android-arm64": "4.57.1", + "@rollup/rollup-darwin-arm64": "4.57.1", + "@rollup/rollup-darwin-x64": "4.57.1", + "@rollup/rollup-freebsd-arm64": "4.57.1", + "@rollup/rollup-freebsd-x64": "4.57.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", + "@rollup/rollup-linux-arm-musleabihf": "4.57.1", + "@rollup/rollup-linux-arm64-gnu": "4.57.1", + "@rollup/rollup-linux-arm64-musl": "4.57.1", + "@rollup/rollup-linux-loong64-gnu": "4.57.1", + "@rollup/rollup-linux-loong64-musl": "4.57.1", + "@rollup/rollup-linux-ppc64-gnu": "4.57.1", + "@rollup/rollup-linux-ppc64-musl": "4.57.1", + "@rollup/rollup-linux-riscv64-gnu": "4.57.1", + "@rollup/rollup-linux-riscv64-musl": "4.57.1", + "@rollup/rollup-linux-s390x-gnu": "4.57.1", + "@rollup/rollup-linux-x64-gnu": "4.57.1", + "@rollup/rollup-linux-x64-musl": "4.57.1", + "@rollup/rollup-openbsd-x64": "4.57.1", + "@rollup/rollup-openharmony-arm64": "4.57.1", + "@rollup/rollup-win32-arm64-msvc": "4.57.1", + "@rollup/rollup-win32-ia32-msvc": "4.57.1", + "@rollup/rollup-win32-x64-gnu": "4.57.1", + "@rollup/rollup-win32-x64-msvc": "4.57.1", "fsevents": "~2.3.2" } }, @@ -1925,11 +3560,30 @@ "loose-envify": "^1.1.0" } }, + "node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true, + "license": "ISC" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -1941,7 +3595,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1950,7 +3604,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, "engines": { "node": ">=14" }, @@ -1958,20 +3611,74 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, "node_modules/source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", - "dev": true, + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, + "node_modules/spawn-wrap": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", + "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^2.0.0", + "is-windows": "^1.0.2", + "make-dir": "^3.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "which": "^2.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/spawn-wrap/node_modules/foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/spawn-wrap/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" + }, "node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, + "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -1989,7 +3696,7 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -2003,7 +3710,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -2012,13 +3719,13 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "license": "MIT" }, "node_modules/string-width-cjs/node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -2027,10 +3734,10 @@ } }, "node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -2046,7 +3753,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -2058,7 +3765,17 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -2085,6 +3802,19 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", @@ -2134,6 +3864,20 @@ "node": ">=14.0.0" } }, + "node_modules/test-exclude": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", + "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==", + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^10.4.1", + "minimatch": "^9.0.4" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/thenify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", @@ -2155,6 +3899,52 @@ "node": ">=0.8" } }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -2173,6 +3963,26 @@ "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", "dev": true }, + "node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, "node_modules/typescript": { "version": "5.5.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", @@ -2186,11 +3996,17 @@ "node": ">=14.17" } }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "devOptional": true, + "license": "MIT" + }, "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", - "dev": true, + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "funding": [ { "type": "opencollective", @@ -2205,9 +4021,10 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.2.0", + "picocolors": "^1.1.1" }, "bin": { "update-browserslist-db": "cli.js" @@ -2222,21 +4039,35 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, - "node_modules/vite": { - "version": "5.2.8", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.8.tgz", - "integrity": "sha512-OyZR+c1CE8yeHw5V5t59aXsUPPVTHMDjEZz8MgguLL/Q7NblxhZUlTu9xSPqlsUO/y+X7dlU05jdhvyycD55DA==", + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "dev": true, + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/vite": { + "version": "7.1.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.11.tgz", + "integrity": "sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==", + "license": "MIT", + "peer": true, "dependencies": { - "esbuild": "^0.20.1", - "postcss": "^8.4.38", - "rollup": "^4.13.0" + "esbuild": "^0.25.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^18.0.0 || >=20.0.0" + "node": "^20.19.0 || >=22.12.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -2245,18 +4076,25 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", "lightningcss": "^1.21.0", - "sass": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" }, "peerDependenciesMeta": { "@types/node": { "optional": true }, + "jiti": { + "optional": true + }, "less": { "optional": true }, @@ -2266,6 +4104,9 @@ "sass": { "optional": true }, + "sass-embedded": { + "optional": true + }, "stylus": { "optional": true }, @@ -2274,14 +4115,69 @@ }, "terser": { "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-plugin-istanbul": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/vite-plugin-istanbul/-/vite-plugin-istanbul-7.2.1.tgz", + "integrity": "sha512-DSPi4ulvYsjnP44sTI5oriNosbM0E6m3uoCxjdxboTtVzxSkFwcDy3/JnSYKebjr+ZToJwVLTms+2CM0rmbbzQ==", + "license": "MIT", + "dependencies": { + "@babel/generator": "^7.28.0", + "@istanbuljs/load-nyc-config": "^1.1.0", + "@types/babel__generator": "7.6.8", + "espree": "^10.3.0", + "istanbul-lib-instrument": "^6.0.3", + "picocolors": "^1.1.1", + "source-map": "^0.7.4", + "test-exclude": "^7.0.1" + }, + "peerDependencies": { + "vite": ">=4 <=7" + } + }, + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true } } }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -2292,11 +4188,18 @@ "node": ">= 8" } }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "dev": true, + "license": "ISC" + }, "node_modules/wrap-ansi": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -2314,7 +4217,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -2331,7 +4234,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -2340,7 +4243,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -2355,13 +4258,13 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "license": "MIT" }, "node_modules/wrap-ansi-cjs/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -2375,7 +4278,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -2383,16 +4286,142 @@ "node": ">=8" } }, - "node_modules/yaml": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.1.tgz", - "integrity": "sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==", + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/write-file-atomic/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", "dev": true, + "license": "ISC" + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" + }, + "node_modules/yaml": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", + "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", + "devOptional": true, + "license": "ISC", "bin": { "yaml": "bin.mjs" }, "engines": { - "node": ">= 14" + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" } } } diff --git a/package.json b/package.json index a748d7d40..53189df91 100644 --- a/package.json +++ b/package.json @@ -8,16 +8,23 @@ "scripts": { "dev": "vite", "build": "vite build", - "preview": "vite preview" + "preview": "vite preview", + "test": "playwright test", + "test:coverage": "nyc --reporter=json-summary --reporter=text playwright test" }, "devDependencies": { + "@playwright/test": "^1.58.1", + "@types/node": "^25.2.0", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", + "vite-plugin-istanbul": "^7.2.1", "autoprefixer": "^10.4.19", + "nyc": "^17.1.0", + "playwright-test-coverage": "^1.2.12", "postcss": "^8.4.38", "tailwindcss": "^3.4.3", "typescript": "^5.5.4", - "vite": "^5.2.8" + "vite": "7.1.11" }, "dependencies": { "preline": "^2.1.0", diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 000000000..f35594089 --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,31 @@ +import { defineConfig, devices } from '@playwright/test'; + +export default defineConfig({ + testDir: './tests', + fullyParallel: true, + forbidOnly: !!process.env.CI, + retries: process.env.CI ? 2 : 0, + workers: process.env.CI ? 1 : undefined, + reporter: 'html', + timeout: 5000, + use: { + baseURL: 'http://localhost:5173', + trace: 'on-first-retry', + }, + + /* Configure projects for major browsers */ + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'], viewport: { width: 800, height: 600 } }, + }, + ], + + /* Run your local dev server before starting the tests */ + webServer: { + command: 'npm run dev', + url: 'http://localhost:5173', + reuseExistingServer: !process.env.CI, + timeout: 5000, + }, +}); \ No newline at end of file diff --git a/tests/auth.spec.ts b/tests/auth.spec.ts new file mode 100644 index 000000000..ef7adb8f9 --- /dev/null +++ b/tests/auth.spec.ts @@ -0,0 +1,5 @@ +import { test } from 'playwright-test-coverage'; + +test('test', async ({ page }) => { + await page.goto('http://localhost:5173/'); +}); \ No newline at end of file diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 000000000..bf46b6ab1 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from 'vite'; +import istanbul from 'vite-plugin-istanbul'; + +export default defineConfig({ + build: { sourcemap: true }, + plugins: [ + istanbul({ + include: ['src/**/*'], + exclude: ['node_modules'], + requireEnv: false, + }), + ], +}); \ No newline at end of file From a7e20891e3dfb6c1e2b1e6449b6dc73f0e50e504 Mon Sep 17 00:00:00 2001 From: cjmot <146262493+cjmot@users.noreply.github.com> Date: Tue, 3 Feb 2026 16:42:14 -0700 Subject: [PATCH 10/42] Update ci and readme --- .github/workflows/ci.yml | 12 ++++++++++++ README.md | 3 ++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 624dcb090..8010da17c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,6 +4,7 @@ on: push: branches: - main + - user-interface-testing workflow_dispatch: jobs: build: @@ -32,6 +33,17 @@ jobs: npm ci && npm run build cp dist/index.html dist/404.html + - name: Run tests + run: | + npx playwright install --with-deps chromium + npm run test:coverage + + - name: Update coverage + run: | + coverage=$(jq '.total.lines.pct' coverage/coverage-summary.json) + color=$(echo "$coverage < 80" | bc | awk '{if ($1) print "red"; else print "green"}') + curl -s -X POST "https://pizza-factory.cs329.click/api/badge/${{ secrets.NET_ID }}/jwtpizzacoverage?label=Coverage&value=$coverage%25&color=$color" -H "authorization: bearer ${{ secrets.FACTORY_API_KEY }}" + - name: Update pages artifact uses: actions/upload-pages-artifact@v3 with: diff --git a/README.md b/README.md index eaa7b9ed9..fa5d4ec89 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ # 🍕 JWT Pizza -![Coverage badge](https://pizza-factory.cs329.click/api/badge/accountId/jwtpizzacoverage?t=1)
+![Coverage badge](https://pizza-factory.cs329.click/api/badge/YOURNETID/jwtpizzacoverage)
[![CI Pipeline](https://github.com/cjmot/jwt-pizza/actions/workflows/ci.yml/badge.svg)](https://github.com/cjmot/jwt-pizza/actions/workflows/ci.yml) + A JSON Web Token, or [JWT](https://jwt.io/introduction), (pronounced JOT) is a digitally signed transfer of information using JSON notation. Because you can validate the digital signature you can buy JWT pizzas with confidence. `JWT Pizza` takes the next stage of digital evolution by allowing you to buy pizzas that you can never actually eat. Not only does JWT exchange bitcoin and give you nothing in return, it also allows for you to be come a franchisee and turn the whole vapor company into an MLM. From 61890c1a1942e3cd43d2ceeb5ec787803dbb6f75 Mon Sep 17 00:00:00 2001 From: cjmot <146262493+cjmot@users.noreply.github.com> Date: Sun, 8 Feb 2026 15:30:24 -0700 Subject: [PATCH 11/42] Add testing plugins and basic test --- .nycrc.json | 8 +- .prettierrc | 6 ++ package-lock.json | 204 +++++++++++++++++++++++++++++++++++++++++++-- package.json | 5 +- tests/auth.spec.ts | 8 +- 5 files changed, 213 insertions(+), 18 deletions(-) create mode 100644 .prettierrc diff --git a/.nycrc.json b/.nycrc.json index 57da1dfb9..8712d48a7 100644 --- a/.nycrc.json +++ b/.nycrc.json @@ -1,7 +1,7 @@ { "check-coverage": true, - "branches": 100, - "lines": 100, - "functions": 100, - "statements": 100 + "branches": 0, + "lines": 80, + "functions": 0, + "statements": 0 } \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..695ce37f6 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,6 @@ +{ + "semi": true, + "singleQuote": true, + "tabIndex": 4, + "trailingComma": "all" +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 3106f961a..bb1853bac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,8 +12,7 @@ "preline": "^2.1.0", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-router-dom": "^6.22.3", - "vite-plugin-istanbul": "^7.2.1" + "react-router-dom": "^6.22.3" }, "devDependencies": { "@playwright/test": "^1.58.1", @@ -24,9 +23,11 @@ "nyc": "^17.1.0", "playwright-test-coverage": "^1.2.12", "postcss": "^8.4.38", + "prettier": "^3.8.1", "tailwindcss": "^3.4.3", "typescript": "^5.5.4", - "vite": "7.1.11" + "vite": "7.1.11", + "vite-plugin-istanbul": "^7.2.1" } }, "node_modules/@alloc/quick-lru": { @@ -45,6 +46,7 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", @@ -59,6 +61,7 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -68,6 +71,7 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -99,6 +103,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -108,6 +113,7 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz", "integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.29.0", @@ -124,6 +130,7 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.28.6", @@ -140,6 +147,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, "license": "ISC", "dependencies": { "yallist": "^3.0.2" @@ -149,6 +157,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -158,6 +167,7 @@ "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -167,6 +177,7 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.28.6", @@ -180,6 +191,7 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.28.6", @@ -197,6 +209,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -206,6 +219,7 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -215,6 +229,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -224,6 +239,7 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.28.6", @@ -237,6 +253,7 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.29.0" @@ -252,6 +269,7 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.28.6", @@ -266,6 +284,7 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.29.0", @@ -284,6 +303,7 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -300,6 +320,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -316,6 +337,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -332,6 +354,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -348,6 +371,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -364,6 +388,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -380,6 +405,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -396,6 +422,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -412,6 +439,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -428,6 +456,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -444,6 +473,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -460,6 +490,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -476,6 +507,7 @@ "cpu": [ "loong64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -492,6 +524,7 @@ "cpu": [ "mips64el" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -508,6 +541,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -524,6 +558,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -540,6 +575,7 @@ "cpu": [ "s390x" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -556,6 +592,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -572,6 +609,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -588,6 +626,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -604,6 +643,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -620,6 +660,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -636,6 +677,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -652,6 +694,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -668,6 +711,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -684,6 +728,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -700,6 +745,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -713,6 +759,7 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, "license": "ISC", "dependencies": { "string-width": "^5.1.2", @@ -730,6 +777,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, "license": "ISC", "dependencies": { "camelcase": "^5.3.1", @@ -746,6 +794,7 @@ "version": "0.1.3", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -755,6 +804,7 @@ "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", @@ -765,6 +815,7 @@ "version": "2.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -775,6 +826,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, "engines": { "node": ">=6.0.0" } @@ -783,12 +835,14 @@ "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -834,6 +888,7 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, "license": "MIT", "optional": true, "engines": { @@ -881,6 +936,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -894,6 +950,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -907,6 +964,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -920,6 +978,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -933,6 +992,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -946,6 +1006,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -959,6 +1020,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -972,6 +1034,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -985,6 +1048,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -998,6 +1062,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1011,6 +1076,7 @@ "cpu": [ "loong64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1024,6 +1090,7 @@ "cpu": [ "loong64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1037,6 +1104,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1050,6 +1118,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1063,6 +1132,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1076,6 +1146,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1089,6 +1160,7 @@ "cpu": [ "s390x" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1102,6 +1174,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1115,6 +1188,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1128,6 +1202,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1141,6 +1216,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1154,6 +1230,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1167,6 +1244,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1180,6 +1258,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1193,6 +1272,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1203,6 +1283,7 @@ "version": "7.6.8", "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.0.0" @@ -1212,13 +1293,14 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, "license": "MIT" }, "node_modules/@types/node": { "version": "25.2.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.0.tgz", "integrity": "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w==", - "devOptional": true, + "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -1254,6 +1336,7 @@ "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, "license": "MIT", "peer": true, "bin": { @@ -1267,6 +1350,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -1290,6 +1374,7 @@ "version": "6.2.2", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -1302,6 +1387,7 @@ "version": "6.2.3", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -1359,6 +1445,7 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, "license": "MIT", "dependencies": { "sprintf-js": "~1.0.2" @@ -1404,12 +1491,14 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true }, "node_modules/baseline-browser-mapping": { "version": "2.9.19", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz", "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==", + "dev": true, "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.js" @@ -1431,6 +1520,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -1451,6 +1541,7 @@ "version": "4.28.1", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, "funding": [ { "type": "opencollective", @@ -1501,6 +1592,7 @@ "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -1519,6 +1611,7 @@ "version": "1.0.30001767", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001767.tgz", "integrity": "sha512-34+zUAMhSH+r+9eKmYG+k2Rpt8XttfE4yXAjoZvkAPs15xcYQhyBYdalJ65BzivAvGRMViEjy6oKr/S91loekQ==", + "dev": true, "funding": [ { "type": "opencollective", @@ -1673,6 +1766,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -1685,6 +1779,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, "license": "MIT" }, "node_modules/commander": { @@ -1714,12 +1809,14 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, "license": "MIT" }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -1752,6 +1849,7 @@ "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -1807,18 +1905,21 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, "license": "MIT" }, "node_modules/electron-to-chromium": { "version": "1.5.286", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz", "integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==", + "dev": true, "license": "ISC" }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, "license": "MIT" }, "node_modules/es6-error": { @@ -1832,6 +1933,7 @@ "version": "0.25.12", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, "hasInstallScript": true, "license": "MIT", "bin": { @@ -1873,6 +1975,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -1882,6 +1985,7 @@ "version": "4.2.1", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1894,6 +1998,7 @@ "version": "10.4.0", "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.15.0", @@ -1911,6 +2016,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", @@ -1991,6 +2097,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, "license": "MIT", "dependencies": { "locate-path": "^5.0.0", @@ -2004,6 +2111,7 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, "license": "ISC", "dependencies": { "cross-spawn": "^7.0.6", @@ -2061,6 +2169,7 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, "hasInstallScript": true, "optional": true, "os": [ @@ -2083,6 +2192,7 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -2102,6 +2212,7 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=8.0.0" @@ -2112,6 +2223,7 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", @@ -2269,6 +2381,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -2329,12 +2442,14 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, "license": "ISC" }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=8" @@ -2357,6 +2472,7 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "@babel/core": "^7.23.9", @@ -2461,6 +2577,7 @@ "version": "3.4.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" @@ -2476,7 +2593,7 @@ "version": "1.21.0", "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", - "devOptional": true, + "dev": true, "bin": { "jiti": "bin/jiti.js" } @@ -2490,6 +2607,7 @@ "version": "3.14.2", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "dev": true, "license": "MIT", "dependencies": { "argparse": "^1.0.7", @@ -2503,6 +2621,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" @@ -2515,6 +2634,7 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, "license": "MIT", "bin": { "json5": "lib/cli.js" @@ -2542,6 +2662,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, "license": "MIT", "dependencies": { "p-locate": "^4.1.0" @@ -2572,6 +2693,7 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, "license": "ISC" }, "node_modules/make-dir": { @@ -2626,6 +2748,7 @@ "version": "9.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -2640,6 +2763,7 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" @@ -2649,6 +2773,7 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, "license": "MIT" }, "node_modules/mz": { @@ -2666,6 +2791,7 @@ "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, "funding": [ { "type": "github", @@ -2697,6 +2823,7 @@ "version": "2.0.27", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true, "license": "MIT" }, "node_modules/normalize-path": { @@ -2866,6 +2993,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, "license": "MIT", "dependencies": { "p-try": "^2.0.0" @@ -2881,6 +3009,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, "license": "MIT", "dependencies": { "p-limit": "^2.2.0" @@ -2906,6 +3035,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -2931,12 +3061,14 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, "license": "BlueOak-1.0.0" }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -2956,6 +3088,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -2971,6 +3104,7 @@ "version": "1.11.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^10.2.0", @@ -2987,6 +3121,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, "license": "ISC" }, "node_modules/picomatch": { @@ -3093,6 +3228,7 @@ "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, "funding": [ { "type": "opencollective", @@ -3247,6 +3383,22 @@ "@popperjs/core": "^2.11.2" } }, + "node_modules/prettier": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/process-on-spawn": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.1.0.tgz", @@ -3407,6 +3559,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -3489,6 +3642,7 @@ "version": "4.57.1", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", + "dev": true, "license": "MIT", "dependencies": { "@types/estree": "1.0.8" @@ -3564,6 +3718,7 @@ "version": "7.7.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -3583,6 +3738,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -3595,6 +3751,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -3604,6 +3761,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, "engines": { "node": ">=14" }, @@ -3615,6 +3773,7 @@ "version": "0.7.6", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">= 12" @@ -3624,6 +3783,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -3672,12 +3832,14 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, "license": "BSD-3-Clause" }, "node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", @@ -3696,6 +3858,7 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -3710,6 +3873,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -3719,12 +3883,14 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, "license": "MIT" }, "node_modules/string-width-cjs/node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -3737,6 +3903,7 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" @@ -3753,6 +3920,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -3765,6 +3933,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -3868,6 +4037,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==", + "dev": true, "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", @@ -3903,6 +4073,7 @@ "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", @@ -3919,6 +4090,7 @@ "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, "license": "MIT", "engines": { "node": ">=12.0.0" @@ -3936,6 +4108,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, "license": "MIT", "peer": true, "engines": { @@ -4000,13 +4173,14 @@ "version": "7.16.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/update-browserslist-db": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, "funding": [ { "type": "opencollective", @@ -4053,8 +4227,8 @@ "version": "7.1.11", "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.11.tgz", "integrity": "sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==", + "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", @@ -4128,6 +4302,7 @@ "version": "7.2.1", "resolved": "https://registry.npmjs.org/vite-plugin-istanbul/-/vite-plugin-istanbul-7.2.1.tgz", "integrity": "sha512-DSPi4ulvYsjnP44sTI5oriNosbM0E6m3uoCxjdxboTtVzxSkFwcDy3/JnSYKebjr+ZToJwVLTms+2CM0rmbbzQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/generator": "^7.28.0", @@ -4147,6 +4322,7 @@ "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, "license": "MIT", "engines": { "node": ">=12.0.0" @@ -4164,6 +4340,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, "license": "MIT", "peer": true, "engines": { @@ -4177,6 +4354,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -4199,6 +4377,7 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", @@ -4217,6 +4396,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -4234,6 +4414,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -4243,6 +4424,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -4258,12 +4440,14 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, "license": "MIT" }, "node_modules/wrap-ansi-cjs/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -4278,6 +4462,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -4324,13 +4509,14 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, "license": "ISC" }, "node_modules/yaml": { "version": "2.8.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", - "devOptional": true, + "dev": true, "license": "ISC", "bin": { "yaml": "bin.mjs" diff --git a/package.json b/package.json index 53189df91..06d3f7f45 100644 --- a/package.json +++ b/package.json @@ -17,14 +17,15 @@ "@types/node": "^25.2.0", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", - "vite-plugin-istanbul": "^7.2.1", "autoprefixer": "^10.4.19", "nyc": "^17.1.0", "playwright-test-coverage": "^1.2.12", "postcss": "^8.4.38", + "prettier": "^3.8.1", "tailwindcss": "^3.4.3", "typescript": "^5.5.4", - "vite": "7.1.11" + "vite": "7.1.11", + "vite-plugin-istanbul": "^7.2.1" }, "dependencies": { "preline": "^2.1.0", diff --git a/tests/auth.spec.ts b/tests/auth.spec.ts index ef7adb8f9..0e2cf631b 100644 --- a/tests/auth.spec.ts +++ b/tests/auth.spec.ts @@ -1,5 +1,7 @@ -import { test } from 'playwright-test-coverage'; +import { test, expect } from 'playwright-test-coverage'; -test('test', async ({ page }) => { - await page.goto('http://localhost:5173/'); +test('home page', async ({ page }) => { + await page.goto('/'); + + expect(await page.title()).toBe('JWT Pizza'); }); \ No newline at end of file From af9847c098405dbbb80c404be8e2944485f9b945 Mon Sep 17 00:00:00 2001 From: cjmot <146262493+cjmot@users.noreply.github.com> Date: Sun, 8 Feb 2026 20:01:59 -0700 Subject: [PATCH 12/42] Reconfigure playwright, update prettier and env --- .env.development | 4 +--- .prettierrc | 3 ++- playwright.config.ts | 52 ++++++++++++++++++++++---------------------- 3 files changed, 29 insertions(+), 30 deletions(-) diff --git a/.env.development b/.env.development index 8595b4211..f606b7c1b 100644 --- a/.env.development +++ b/.env.development @@ -1,4 +1,2 @@ -VITE_PIZZA_SERVICE_URL=https://pizza-service.cs329.click +VITE_PIZZA_SERVICE_URL=http://localhost:3000 VITE_PIZZA_FACTORY_URL=https://pizza-factory.cs329.click - -# TODO: Update service variable to run tests \ No newline at end of file diff --git a/.prettierrc b/.prettierrc index 695ce37f6..f6c4ec803 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,6 +1,7 @@ { "semi": true, "singleQuote": true, - "tabIndex": 4, + "printWidth": 100, + "tabWidth": 4, "trailingComma": "all" } \ No newline at end of file diff --git a/playwright.config.ts b/playwright.config.ts index f35594089..f9a053247 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,31 +1,31 @@ import { defineConfig, devices } from '@playwright/test'; export default defineConfig({ - testDir: './tests', - fullyParallel: true, - forbidOnly: !!process.env.CI, - retries: process.env.CI ? 2 : 0, - workers: process.env.CI ? 1 : undefined, - reporter: 'html', - timeout: 5000, - use: { - baseURL: 'http://localhost:5173', - trace: 'on-first-retry', - }, - - /* Configure projects for major browsers */ - projects: [ - { - name: 'chromium', - use: { ...devices['Desktop Chrome'], viewport: { width: 800, height: 600 } }, + testDir: './tests', + fullyParallel: true, + forbidOnly: !!process.env.CI, + retries: process.env.CI ? 2 : 0, + workers: process.env.CI ? 1 : undefined, + reporter: 'html', + timeout: 5000, + use: { + baseURL: 'http://localhost:5173', + trace: 'retain-on-failure' }, - ], - /* Run your local dev server before starting the tests */ - webServer: { - command: 'npm run dev', - url: 'http://localhost:5173', - reuseExistingServer: !process.env.CI, - timeout: 5000, - }, -}); \ No newline at end of file + /* Configure projects for major browsers */ + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'], viewport: { width: 800, height: 600 } }, + }, + ], + + /* Run your local dev server before starting the tests */ + webServer: { + command: 'npm run dev', + url: 'http://localhost:5173', + reuseExistingServer: !process.env.CI, + timeout: 5000, + }, +}); From 4fcf9fa99fb9f52891f28155f903fdfe61755c1b Mon Sep 17 00:00:00 2001 From: cjmot <146262493+cjmot@users.noreply.github.com> Date: Sun, 8 Feb 2026 20:02:20 -0700 Subject: [PATCH 13/42] Add auth tests and static ui tests --- playwright.config.ts | 2 +- tests/auth.spec.ts | 149 +++++++++++++++++++++++++++++++++++++++++-- tests/ui.spec.ts | 14 ++++ 3 files changed, 160 insertions(+), 5 deletions(-) create mode 100644 tests/ui.spec.ts diff --git a/playwright.config.ts b/playwright.config.ts index f9a053247..9bd2197bc 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -10,7 +10,7 @@ export default defineConfig({ timeout: 5000, use: { baseURL: 'http://localhost:5173', - trace: 'retain-on-failure' + trace: 'retain-on-failure', }, /* Configure projects for major browsers */ diff --git a/tests/auth.spec.ts b/tests/auth.spec.ts index 0e2cf631b..3f6615268 100644 --- a/tests/auth.spec.ts +++ b/tests/auth.spec.ts @@ -1,7 +1,148 @@ import { test, expect } from 'playwright-test-coverage'; +import { Page } from 'playwright'; +import { User, Role } from '../src/service/pizzaService'; -test('home page', async ({ page }) => { - await page.goto('/'); +async function basicInit(page: Page) { + let loggedInUser: User | undefined; + const validUsers: Record = { + 'd@jwt.com': { + id: '3', + name: 'Pizza Diner', + email: 'd@jwt.com', + password: 'a', + roles: [{ role: Role.Diner }], + }, + }; - expect(await page.title()).toBe('JWT Pizza'); -}); \ No newline at end of file + // Authorize login for the given user + await page.route('*/**/api/auth', async (route) => { + const loginReq = route.request().postDataJSON(); + if (route.request().method() === 'DELETE') { + loggedInUser = undefined; + await route.fulfill({ json: { message: 'logged out successfully' } }); + return; + } + const user = validUsers[loginReq.email]; + if (!user || user.password !== loginReq.password) { + await route.fulfill({ status: 401, json: { error: 'Unauthorized' } }); + return; + } + loggedInUser = validUsers[loginReq.email]; + const loginRes = { + user: loggedInUser, + token: 'abcdef', + }; + expect(route.request().method()).toBe('PUT'); + await route.fulfill({ json: loginRes }); + }); + + // Return the currently logged in user + await page.route('*/**/api/user/me', async (route) => { + expect(route.request().method()).toBe('GET'); + await route.fulfill({ json: loggedInUser }); + }); + + // A standard menu + await page.route('*/**/api/order/menu', async (route) => { + const menuRes = [ + { + id: 1, + title: 'Veggie', + image: 'pizza1.png', + price: 0.0038, + description: 'A garden of delight', + }, + { + id: 2, + title: 'Pepperoni', + image: 'pizza2.png', + price: 0.0042, + description: 'Spicy treat', + }, + ]; + expect(route.request().method()).toBe('GET'); + await route.fulfill({ json: menuRes }); + }); + + // Standard franchises and stores + await page.route(/\/api\/franchise(\?.*)?$/, async (route) => { + const franchiseRes = { + franchises: [ + { + id: 2, + name: 'LotaPizza', + stores: [ + { id: 4, name: 'Lehi' }, + { id: 5, name: 'Springville' }, + { id: 6, name: 'American Fork' }, + ], + }, + { id: 3, name: 'PizzaCorp', stores: [{ id: 7, name: 'Spanish Fork' }] }, + { id: 4, name: 'topSpot', stores: [] }, + ], + }; + expect(route.request().method()).toBe('GET'); + await route.fulfill({ json: franchiseRes }); + }); + + // Order a pizza. + await page.route('*/**/api/order', async (route) => { + const orderReq = route.request().postDataJSON(); + const orderRes = { + order: { ...orderReq, id: 23 }, + jwt: 'eyJpYXQ', + }; + expect(route.request().method()).toBe('POST'); + await route.fulfill({ json: orderRes }); + }); + + await page.goto('/'); +} + +test('login and logout', async ({ page }) => { + await basicInit(page); + + // login, check logged in + await page.getByRole('link', { name: 'Login' }).click(); + await page.getByRole('textbox', { name: 'Email address' }).fill('d@jwt.com'); + await page.getByRole('textbox', { name: 'Password' }).fill('a'); + await page.getByRole('button', { name: 'Login' }).click(); + + await expect(page.getByRole('link', { name: 'PD' })).toBeVisible(); + + // Logout, check logged out + await page.getByRole('link', { name: 'Logout' }).click(); + await expect(page.getByLabel('Global')).toContainText('JWT PizzaOrderFranchiseLoginRegister'); +}); + +test('purchase with login', async ({ page }) => { + await basicInit(page); + + // Go to order page + await page.getByRole('button', { name: 'Order now' }).click(); + + // Create order + await expect(page.locator('h2')).toContainText('Awesome is a click away'); + await page.getByRole('combobox').selectOption('4'); + await page.getByRole('link', { name: 'Image Description Veggie A' }).click(); + await page.getByRole('link', { name: 'Image Description Pepperoni' }).click(); + await expect(page.locator('form')).toContainText('Selected pizzas: 2'); + await page.getByRole('button', { name: 'Checkout' }).click(); + + // Login + await page.getByPlaceholder('Email address').click(); + await page.getByPlaceholder('Email address').fill('d@jwt.com'); + await page.getByPlaceholder('Email address').press('Tab'); + await page.getByPlaceholder('Password').fill('a'); + await page.getByRole('button', { name: 'Login' }).click(); + + // Pay + await expect(page.getByRole('main')).toContainText('Send me those 2 pizzas right now!'); + await expect(page.locator('tbody')).toContainText('Veggie'); + await expect(page.locator('tbody')).toContainText('Pepperoni'); + await expect(page.locator('tfoot')).toContainText('0.008 ₿'); + await page.getByRole('button', { name: 'Pay now' }).click(); + + // Check balance + await expect(page.getByText('0.008')).toBeVisible(); +}); diff --git a/tests/ui.spec.ts b/tests/ui.spec.ts new file mode 100644 index 000000000..81f6834f3 --- /dev/null +++ b/tests/ui.spec.ts @@ -0,0 +1,14 @@ +import { test, expect } from 'playwright-test-coverage'; + +test('history, about', async ({ page }) => { + await page.goto('/'); + // About + await page.getByRole('link', { name: 'About' }).click(); + await expect(page.getByText('The secret sauce')).toBeVisible(); + await expect(page.getByRole('img').nth(3)).toBeVisible(); + + // History + await page.getByRole('link', { name: 'History' }).click(); + await expect(page.getByText('Mama Rucci, my my')).toBeVisible(); + await expect(page.getByRole('main').getByRole('img')).toBeVisible(); +}); From 106472419c77ca863ca6e205aee120f94d9d7056 Mon Sep 17 00:00:00 2001 From: cjmot <146262493+cjmot@users.noreply.github.com> Date: Mon, 9 Feb 2026 20:15:11 -0700 Subject: [PATCH 14/42] moved basicInit to a helper file --- tests/auth.spec.ts | 100 +----------------------------- tests/helpers.ts | 150 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+), 99 deletions(-) create mode 100644 tests/helpers.ts diff --git a/tests/auth.spec.ts b/tests/auth.spec.ts index 3f6615268..9bb17f7fe 100644 --- a/tests/auth.spec.ts +++ b/tests/auth.spec.ts @@ -1,103 +1,5 @@ import { test, expect } from 'playwright-test-coverage'; -import { Page } from 'playwright'; -import { User, Role } from '../src/service/pizzaService'; - -async function basicInit(page: Page) { - let loggedInUser: User | undefined; - const validUsers: Record = { - 'd@jwt.com': { - id: '3', - name: 'Pizza Diner', - email: 'd@jwt.com', - password: 'a', - roles: [{ role: Role.Diner }], - }, - }; - - // Authorize login for the given user - await page.route('*/**/api/auth', async (route) => { - const loginReq = route.request().postDataJSON(); - if (route.request().method() === 'DELETE') { - loggedInUser = undefined; - await route.fulfill({ json: { message: 'logged out successfully' } }); - return; - } - const user = validUsers[loginReq.email]; - if (!user || user.password !== loginReq.password) { - await route.fulfill({ status: 401, json: { error: 'Unauthorized' } }); - return; - } - loggedInUser = validUsers[loginReq.email]; - const loginRes = { - user: loggedInUser, - token: 'abcdef', - }; - expect(route.request().method()).toBe('PUT'); - await route.fulfill({ json: loginRes }); - }); - - // Return the currently logged in user - await page.route('*/**/api/user/me', async (route) => { - expect(route.request().method()).toBe('GET'); - await route.fulfill({ json: loggedInUser }); - }); - - // A standard menu - await page.route('*/**/api/order/menu', async (route) => { - const menuRes = [ - { - id: 1, - title: 'Veggie', - image: 'pizza1.png', - price: 0.0038, - description: 'A garden of delight', - }, - { - id: 2, - title: 'Pepperoni', - image: 'pizza2.png', - price: 0.0042, - description: 'Spicy treat', - }, - ]; - expect(route.request().method()).toBe('GET'); - await route.fulfill({ json: menuRes }); - }); - - // Standard franchises and stores - await page.route(/\/api\/franchise(\?.*)?$/, async (route) => { - const franchiseRes = { - franchises: [ - { - id: 2, - name: 'LotaPizza', - stores: [ - { id: 4, name: 'Lehi' }, - { id: 5, name: 'Springville' }, - { id: 6, name: 'American Fork' }, - ], - }, - { id: 3, name: 'PizzaCorp', stores: [{ id: 7, name: 'Spanish Fork' }] }, - { id: 4, name: 'topSpot', stores: [] }, - ], - }; - expect(route.request().method()).toBe('GET'); - await route.fulfill({ json: franchiseRes }); - }); - - // Order a pizza. - await page.route('*/**/api/order', async (route) => { - const orderReq = route.request().postDataJSON(); - const orderRes = { - order: { ...orderReq, id: 23 }, - jwt: 'eyJpYXQ', - }; - expect(route.request().method()).toBe('POST'); - await route.fulfill({ json: orderRes }); - }); - - await page.goto('/'); -} +import { basicInit } from './helpers'; test('login and logout', async ({ page }) => { await basicInit(page); diff --git a/tests/helpers.ts b/tests/helpers.ts new file mode 100644 index 000000000..2d23864e0 --- /dev/null +++ b/tests/helpers.ts @@ -0,0 +1,150 @@ +import { Page } from '@playwright/test'; +import { Role, User } from '../src/service/pizzaService'; +import { expect } from 'playwright-test-coverage'; + +async function basicInit(page: Page) { + let loggedInUser: User | undefined; + + await page.addInitScript(() => { + localStorage.clear(); + sessionStorage.clear(); + }); + const validUsers: Record = { + 'd@jwt.com': { + id: '3', + name: 'Pizza Diner', + email: 'd@jwt.com', + password: 'a', + roles: [{ role: Role.Diner }], + }, + 'a@jwt.com': { + id: '5', + name: 'Pizza Admin', + email: 'a@jwt.com', + password: 'admin', + roles: [{ role: Role.Admin }], + }, + }; + + let validFranchises = [ + { + id: 2, + name: 'LotaPizza', + stores: [ + { id: 4, name: 'Lehi' }, + { id: 5, name: 'Springville' }, + { id: 6, name: 'American Fork' }, + ], + }, + { id: 3, name: 'PizzaCorp', stores: [{ id: 7, name: 'Spanish Fork' }] }, + { id: 4, name: 'topSpot', stores: [] }, + ]; + + // Authorize login for the given user + await page.route('*/**/api/auth', async (route) => { + if (route.request().method() === 'DELETE') { + loggedInUser = undefined; + await route.fulfill({ json: { message: 'logged out successfully' } }); + return; + } + const loginReq = route.request().postDataJSON(); + const user = validUsers[loginReq.email]; + if (!user || user.password !== loginReq.password) { + await route.fulfill({ status: 401, json: { error: 'Unauthorized' } }); + return; + } + loggedInUser = validUsers[loginReq.email]; + const loginRes = { + user: loggedInUser, + token: 'abcdef', + }; + expect(route.request().method()).toBe('PUT'); + await route.fulfill({ json: loginRes }); + }); + + // Return the currently logged in user + await page.route('*/**/api/user/me', async (route) => { + expect(route.request().method()).toBe('GET'); + await route.fulfill({ json: loggedInUser }); + }); + + // A standard menu + await page.route('*/**/api/order/menu', async (route) => { + const menuRes = [ + { + id: 1, + title: 'Veggie', + image: 'pizza1.png', + price: 0.0038, + description: 'A garden of delight', + }, + { + id: 2, + title: 'Pepperoni', + image: 'pizza2.png', + price: 0.0042, + description: 'Spicy treat', + }, + ]; + expect(route.request().method()).toBe('GET'); + await route.fulfill({ json: menuRes }); + }); + + // Create a franchise + await page.route(/\/api\/franchise$/, async (route) => { + expect(route.request().method()).toBe('POST'); + const franchiseReq = route.request().postDataJSON(); + expect(franchiseReq.admins[0].email).toBe(loggedInUser?.email); + expect(franchiseReq.name).toBe('newFranchise'); + const newFranchise = { + name: franchiseReq.name, + id: 8, + admins: [ + { + name: loggedInUser?.name, + email: franchiseReq.admins[0].email, + id: loggedInUser?.id, + }, + ], + }; + validFranchises.push({ ...newFranchise, stores: [] }); + await route.fulfill({ json: newFranchise }); + }); + + // Delete a franchise + await page.route(/\/api\/franchise\/(\d)$/, async (route) => { + expect(route.request().method()).toBe('DELETE'); + const franchiseId = route.request().url().split('/').pop(); + if (franchiseId) { + validFranchises = validFranchises.filter((f) => f.id !== parseInt(franchiseId)); + await route.fulfill({ json: { message: 'franchise deleted' } }); + return; + } else { + await route.fulfill({ status: 400, json: { error: 'missing franchise id' } }); + } + }); + + // Get franchises + await page.route(/\/api\/franchise(\?.*)$/, async (route) => { + const franchiseRes = { + franchises: validFranchises, + }; + expect(route.request().method()).toBe('GET'); + await route.fulfill({ json: franchiseRes }); + }); + + // Order a pizza. + await page.route('*/**/api/order', async (route) => { + const orderReq = route.request().postDataJSON(); + const orderRes = { + order: { ...orderReq, id: 23 }, + jwt: 'eyJpYXQ', + }; + expect(route.request().method()).toBe('POST'); + await route.fulfill({ json: orderRes }); + }); + + await page.goto('/'); +} + +export { basicInit }; From a76b79c479d1e58c765e2a4a0f0360b68df841b8 Mon Sep 17 00:00:00 2001 From: cjmot <146262493+cjmot@users.noreply.github.com> Date: Mon, 9 Feb 2026 20:15:33 -0700 Subject: [PATCH 15/42] add tests for creating and closing franchises and stores --- tests/adminFunctions.spec.ts | 60 ++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 tests/adminFunctions.spec.ts diff --git a/tests/adminFunctions.spec.ts b/tests/adminFunctions.spec.ts new file mode 100644 index 000000000..9c125c4ec --- /dev/null +++ b/tests/adminFunctions.spec.ts @@ -0,0 +1,60 @@ +import { test, expect } from 'playwright-test-coverage'; +import { basicInit } from './helpers'; + +test('create and close franchise', async ({ page }) => { + await basicInit(page); + + await page.getByRole('link', { name: 'Login' }).click(); + await page.getByRole('textbox', { name: 'Email address' }).fill('a@jwt.com'); + await page.getByRole('textbox', { name: 'Password' }).fill('admin'); + await page.getByRole('button', { name: 'Login' }).click(); + await expect(page.getByRole('link', { name: 'Admin' })).toBeVisible(); + + // Admin page + await page.getByRole('link', { name: 'Admin' }).click(); + await expect(page.getByText("Mama Ricci's kitchen")).toBeVisible(); + await expect(page.getByText('LotaPizza')).toBeVisible(); + await expect(page.getByRole('cell', { name: 'Lehi' })).toBeVisible(); + await expect(page.getByRole('cell', { name: 'Springville' })).toBeVisible(); + await expect(page.getByRole('cell', { name: 'American Fork' })).toBeVisible(); + + // Create franchise + await page.getByRole('button', { name: 'Add Franchise' }).click(); + await page.getByRole('textbox', { name: 'franchise name' }).click(); + await page.getByRole('textbox', { name: 'franchise name' }).fill('newFranchise'); + await page.getByRole('textbox', { name: 'franchisee admin email' }).click(); + await page.getByRole('textbox', { name: 'franchisee admin email' }).fill('a@jwt.com'); + await page.getByRole('button', { name: 'Create' }).click(); + await Promise.all([ + page.waitForRequest((r) => r.url().includes('/api/franchise') && r.method() === 'GET'), + ]); + await expect(page.getByRole('cell', { name: 'newFranchise' })).toBeVisible(); + await expect(page.getByRole('cell', { name: 'Pizza Admin' })).toBeVisible(); + await page + .getByRole('row', { name: 'newFranchise Pizza Admin Close' }) + .getByRole('button') + .click(); + await expect(page.getByText('Sorry to see you go')).toBeVisible(); + await expect(page.getByText('newFranchise')).toBeVisible(); + await page.getByRole('button', { name: 'Close' }).click(); + await expect(page.getByRole('cell', { name: 'LotaPizza' })).toBeVisible(); +}); + +test('create and close store', async ({ page }) => { + await basicInit(page); + + // Login and go to admin page + await page.getByRole('link', { name: 'Login' }).click(); + await page.getByRole('textbox', { name: 'Email address' }).fill('a@jwt.com'); + await page.getByRole('textbox', { name: 'Password' }).fill('admin'); + await page.getByRole('button', { name: 'Login' }).click(); + await page.getByRole('link', { name: 'Admin' }).click(); + + // Close Spanish Fork store + await page.getByRole('row', { name: 'Spanish Fork ₿ Close' }).getByRole('button').click(); + await expect(page.getByRole('main')).toContainText( + 'Are you sure you want to close the PizzaCorp store Spanish Fork ? This cannot be restored. All outstanding revenue will not be refunded.', + ); + await page.getByRole('button', { name: 'Close' }).click(); + await expect(page.getByRole('cell', { name: 'Spanish Fork' })).toHaveCount(0); +}); From 5f117ca77f2477990a17285398f0cf9676d3229e Mon Sep 17 00:00:00 2001 From: cjmot <146262493+cjmot@users.noreply.github.com> Date: Mon, 9 Feb 2026 21:05:54 -0700 Subject: [PATCH 16/42] more tests for deleting and creating stores --- tests/adminFunctions.spec.ts | 6 +-- tests/helpers.ts | 79 ++++++++++++++++++++++++++++++------ 2 files changed, 69 insertions(+), 16 deletions(-) diff --git a/tests/adminFunctions.spec.ts b/tests/adminFunctions.spec.ts index 9c125c4ec..3f1f9a90c 100644 --- a/tests/adminFunctions.spec.ts +++ b/tests/adminFunctions.spec.ts @@ -51,10 +51,10 @@ test('create and close store', async ({ page }) => { await page.getByRole('link', { name: 'Admin' }).click(); // Close Spanish Fork store - await page.getByRole('row', { name: 'Spanish Fork ₿ Close' }).getByRole('button').click(); + await page.getByRole('row', { name: 'Lehi ₿ Close' }).getByRole('button').click(); await expect(page.getByRole('main')).toContainText( - 'Are you sure you want to close the PizzaCorp store Spanish Fork ? This cannot be restored. All outstanding revenue will not be refunded.', + 'Are you sure you want to close the LotaPizza store Lehi ? This cannot be restored. All outstanding revenue will not be refunded.', ); await page.getByRole('button', { name: 'Close' }).click(); - await expect(page.getByRole('cell', { name: 'Spanish Fork' })).toHaveCount(0); + await expect(page.getByRole('cell', { name: 'Lehi' })).toHaveCount(0); }); diff --git a/tests/helpers.ts b/tests/helpers.ts index 2d23864e0..9b937494a 100644 --- a/tests/helpers.ts +++ b/tests/helpers.ts @@ -26,18 +26,24 @@ async function basicInit(page: Page) { }, }; - let validFranchises = [ + let validFranchises: { + id: string; + name: string; + stores: { id: string; name: string }[]; + admins: User[]; + }[] = [ { - id: 2, + id: '2', name: 'LotaPizza', stores: [ - { id: 4, name: 'Lehi' }, - { id: 5, name: 'Springville' }, - { id: 6, name: 'American Fork' }, + { id: '4', name: 'Lehi' }, + { id: '5', name: 'Springville' }, + { id: '6', name: 'American Fork' }, ], + admins: [], }, - { id: 3, name: 'PizzaCorp', stores: [{ id: 7, name: 'Spanish Fork' }] }, - { id: 4, name: 'topSpot', stores: [] }, + { id: '3', name: 'PizzaCorp', stores: [{ id: '7', name: 'Spanish Fork' }], admins: [] }, + { id: '4', name: 'topSpot', stores: [], admins: [] }, ]; // Authorize login for the given user @@ -72,14 +78,14 @@ async function basicInit(page: Page) { await page.route('*/**/api/order/menu', async (route) => { const menuRes = [ { - id: 1, + id: '1', title: 'Veggie', image: 'pizza1.png', price: 0.0038, description: 'A garden of delight', }, { - id: 2, + id: '2', title: 'Pepperoni', image: 'pizza2.png', price: 0.0042, @@ -98,10 +104,10 @@ async function basicInit(page: Page) { expect(franchiseReq.name).toBe('newFranchise'); const newFranchise = { name: franchiseReq.name, - id: 8, + id: '8', admins: [ { - name: loggedInUser?.name, + name: loggedInUser?.name || '', email: franchiseReq.admins[0].email, id: loggedInUser?.id, }, @@ -112,11 +118,11 @@ async function basicInit(page: Page) { }); // Delete a franchise - await page.route(/\/api\/franchise\/(\d)$/, async (route) => { + await page.route(/\/api\/franchise\/(\d+)$/, async (route) => { expect(route.request().method()).toBe('DELETE'); const franchiseId = route.request().url().split('/').pop(); if (franchiseId) { - validFranchises = validFranchises.filter((f) => f.id !== parseInt(franchiseId)); + validFranchises = validFranchises.filter((f) => f.id !== franchiseId); await route.fulfill({ json: { message: 'franchise deleted' } }); return; } else { @@ -144,6 +150,53 @@ async function basicInit(page: Page) { await route.fulfill({ json: orderRes }); }); + // Delete and Create store + await page.route(/\/api\/franchise\/(\d+)\/store(\/\d+)?/, async (route) => { + console.log('Route: ', route.request().url()); + if (route.request().method() === 'DELETE') { + const storeId = route.request().url().split('/').pop(); + const franchiseId = route + .request() + .url() + .match(/\/franchise\/(\d+)\/store/)?.[1]; + console.log(storeId, franchiseId); + if (!storeId || !franchiseId) { + await route.fulfill({ + status: 400, + json: { error: 'missing store or franchise id' }, + }); + return; + } + const franchise = validFranchises.find((f) => f.id === franchiseId); + if (!franchise) { + await route.fulfill({ status: 404, json: { error: 'franchise not found' } }); + return; + } + franchise.stores = franchise.stores.filter((s) => s.id !== storeId); + console.log('ValidFranchises: ', validFranchises); + await route.fulfill({ json: { message: 'store deleted' } }); + return; + } else if (route.request().method() === 'POST') { + const franchiseId = route + .request() + .url() + .match(/\/franchise\/(\d+)\/store/)?.[1]; + if (!franchiseId) { + await route.fulfill({ status: 400, json: { error: 'missing franchise id' } }); + return; + } + const storeReq = route.request().postDataJSON(); + const newStore = { ...storeReq, id: '12' }; + const franchise = validFranchises.find((f) => f.id === franchiseId); + if (!franchise) { + await route.fulfill({ status: 404, json: { error: 'franchise not found' } }); + return; + } + franchise.stores.push(newStore); + await route.fulfill({ json: newStore }); + } + }); + await page.goto('/'); } From 6fe0afa80352b98adcb8ed992b4d41cef09c2695 Mon Sep 17 00:00:00 2001 From: cjmot <146262493+cjmot@users.noreply.github.com> Date: Mon, 9 Feb 2026 21:07:02 -0700 Subject: [PATCH 17/42] remove console logs --- tests/helpers.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/helpers.ts b/tests/helpers.ts index 9b937494a..a774d755c 100644 --- a/tests/helpers.ts +++ b/tests/helpers.ts @@ -152,14 +152,12 @@ async function basicInit(page: Page) { // Delete and Create store await page.route(/\/api\/franchise\/(\d+)\/store(\/\d+)?/, async (route) => { - console.log('Route: ', route.request().url()); if (route.request().method() === 'DELETE') { const storeId = route.request().url().split('/').pop(); const franchiseId = route .request() .url() .match(/\/franchise\/(\d+)\/store/)?.[1]; - console.log(storeId, franchiseId); if (!storeId || !franchiseId) { await route.fulfill({ status: 400, @@ -173,7 +171,6 @@ async function basicInit(page: Page) { return; } franchise.stores = franchise.stores.filter((s) => s.id !== storeId); - console.log('ValidFranchises: ', validFranchises); await route.fulfill({ json: { message: 'store deleted' } }); return; } else if (route.request().method() === 'POST') { From 2220aa995a9c77200538767a09b128ab2f407ee7 Mon Sep 17 00:00:00 2001 From: cjmot <146262493+cjmot@users.noreply.github.com> Date: Mon, 9 Feb 2026 22:03:57 -0700 Subject: [PATCH 18/42] updated comments --- tests/adminFunctions.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/adminFunctions.spec.ts b/tests/adminFunctions.spec.ts index 3f1f9a90c..483b9330a 100644 --- a/tests/adminFunctions.spec.ts +++ b/tests/adminFunctions.spec.ts @@ -40,7 +40,7 @@ test('create and close franchise', async ({ page }) => { await expect(page.getByRole('cell', { name: 'LotaPizza' })).toBeVisible(); }); -test('create and close store', async ({ page }) => { +test('create and close store as admin', async ({ page }) => { await basicInit(page); // Login and go to admin page From 780907fced623afd1a138877a6300b868ea3a1e8 Mon Sep 17 00:00:00 2001 From: cjmot <146262493+cjmot@users.noreply.github.com> Date: Tue, 10 Feb 2026 11:18:28 -0700 Subject: [PATCH 19/42] add tests for franchisee functions --- tests/adminFunctions.spec.ts | 2 +- tests/franchiseeFunctions.spec.ts | 32 +++++++++++++++++++++ tests/helpers.ts | 48 ++++++++++++++++++++++--------- 3 files changed, 68 insertions(+), 14 deletions(-) create mode 100644 tests/franchiseeFunctions.spec.ts diff --git a/tests/adminFunctions.spec.ts b/tests/adminFunctions.spec.ts index 483b9330a..8811f15df 100644 --- a/tests/adminFunctions.spec.ts +++ b/tests/adminFunctions.spec.ts @@ -51,7 +51,7 @@ test('create and close store as admin', async ({ page }) => { await page.getByRole('link', { name: 'Admin' }).click(); // Close Spanish Fork store - await page.getByRole('row', { name: 'Lehi ₿ Close' }).getByRole('button').click(); + await page.getByRole('row', { name: 'Lehi 450 ₿ Close' }).getByRole('button').click(); await expect(page.getByRole('main')).toContainText( 'Are you sure you want to close the LotaPizza store Lehi ? This cannot be restored. All outstanding revenue will not be refunded.', ); diff --git a/tests/franchiseeFunctions.spec.ts b/tests/franchiseeFunctions.spec.ts new file mode 100644 index 000000000..a4f5097bf --- /dev/null +++ b/tests/franchiseeFunctions.spec.ts @@ -0,0 +1,32 @@ +import { test, expect } from 'playwright-test-coverage'; +import { basicInit } from './helpers'; + +test('create and close store as franchisee', async ({ page }) => { + await basicInit(page); + + await page.getByRole('link', { name: 'Login' }).click(); + await page.getByRole('textbox', { name: 'Email address' }).fill('f@jwt.com'); + await page.getByRole('textbox', { name: 'Password' }).fill('f'); + await page.getByRole('button', { name: 'Login' }).click(); + await page + .getByRole('navigation', { name: 'Global' }) + .getByRole('link', { name: 'Franchise' }) + .click(); + await expect(page.getByText('LotaPizza')).toBeVisible(); + await expect(page.getByText('Lehi')).toBeVisible(); + + // Create and close new store + await page.getByRole('button', { name: 'Create store' }).click(); + await expect(page.getByText('Create store')).toBeVisible(); + await page.getByRole('textbox', { name: 'store name' }).fill('newStore'); + await page.getByRole('button', { name: 'Create' }).click(); + await Promise.all([page.waitForResponse((r) => r.url().includes('/api/franchise'))]); + await expect(page.locator('tbody')).toContainText('newStore'); + await page.getByRole('row', { name: 'newStore 0 ₿ Close' }).getByRole('button').click(); + await expect(page.getByRole('main')).toContainText( + 'Are you sure you want to close the LotaPizza store newStore ? This cannot be restored. All outstanding revenue will not be refunded.', + ); + await page.getByRole('button', { name: 'Close' }).click(); + await Promise.all([page.waitForResponse((r) => r.url().includes('/api/franchise'))]); + await expect(page.locator('tbody')).not.toContainText('newStore'); +}); diff --git a/tests/helpers.ts b/tests/helpers.ts index a774d755c..1bad951d4 100644 --- a/tests/helpers.ts +++ b/tests/helpers.ts @@ -17,6 +17,13 @@ async function basicInit(page: Page) { password: 'a', roles: [{ role: Role.Diner }], }, + 'f@jwt.com': { + id: '4', + name: 'Pizza Franchisee', + email: 'f@jwt.com', + password: 'f', + roles: [{ role: Role.Franchisee }], + }, 'a@jwt.com': { id: '5', name: 'Pizza Admin', @@ -29,20 +36,25 @@ async function basicInit(page: Page) { let validFranchises: { id: string; name: string; - stores: { id: string; name: string }[]; + stores: { id: string; name: string; franchiseId: string; totalRevenue?: number }[]; admins: User[]; }[] = [ { id: '2', name: 'LotaPizza', stores: [ - { id: '4', name: 'Lehi' }, - { id: '5', name: 'Springville' }, - { id: '6', name: 'American Fork' }, + { id: '4', name: 'Lehi', franchiseId: '2', totalRevenue: 450 }, + { id: '5', name: 'Springville', franchiseId: '2', totalRevenue: 5 }, + { id: '6', name: 'American Fork', franchiseId: '2', totalRevenue: 890 }, ], + admins: [{ id: '4', name: 'Pizza Franchisee', email: 'f@jwt.com' }], + }, + { + id: '3', + name: 'PizzaCorp', + stores: [{ id: '7', name: 'Spanish Fork', franchiseId: '3', totalRevenue: 0 }], admins: [], }, - { id: '3', name: 'PizzaCorp', stores: [{ id: '7', name: 'Spanish Fork' }], admins: [] }, { id: '4', name: 'topSpot', stores: [], admins: [] }, ]; @@ -117,14 +129,22 @@ async function basicInit(page: Page) { await route.fulfill({ json: newFranchise }); }); - // Delete a franchise + // Delete a franchise or get a user's franchises await page.route(/\/api\/franchise\/(\d+)$/, async (route) => { - expect(route.request().method()).toBe('DELETE'); const franchiseId = route.request().url().split('/').pop(); if (franchiseId) { - validFranchises = validFranchises.filter((f) => f.id !== franchiseId); - await route.fulfill({ json: { message: 'franchise deleted' } }); - return; + if (route.request().method() === 'DELETE') { + validFranchises = validFranchises.filter((f) => f.id !== franchiseId); + await route.fulfill({ json: { message: 'franchise deleted' } }); + return; + } else if (route.request().method() === 'GET') { + const userId = franchiseId; + const franchises = validFranchises.filter((f) => + f.admins.find((a) => a.id === userId), + ); + await route.fulfill({ json: franchises }); + return; + } } else { await route.fulfill({ status: 400, json: { error: 'missing franchise id' } }); } @@ -174,6 +194,7 @@ async function basicInit(page: Page) { await route.fulfill({ json: { message: 'store deleted' } }); return; } else if (route.request().method() === 'POST') { + const storeReq = route.request().postDataJSON(); const franchiseId = route .request() .url() @@ -182,15 +203,16 @@ async function basicInit(page: Page) { await route.fulfill({ status: 400, json: { error: 'missing franchise id' } }); return; } - const storeReq = route.request().postDataJSON(); - const newStore = { ...storeReq, id: '12' }; + const newStore = { name: storeReq.name, id: '12', franchiseId, totalRevenue: 0 }; const franchise = validFranchises.find((f) => f.id === franchiseId); if (!franchise) { await route.fulfill({ status: 404, json: { error: 'franchise not found' } }); return; } franchise.stores.push(newStore); - await route.fulfill({ json: newStore }); + await route.fulfill({ + json: { id: newStore.id, name: newStore.name, franchiseId }, + }); } }); From bd67718745d8b2c0f50532b9e9994cad31f32596 Mon Sep 17 00:00:00 2001 From: cjmot <146262493+cjmot@users.noreply.github.com> Date: Tue, 10 Feb 2026 11:22:52 -0700 Subject: [PATCH 20/42] add docs to ui test --- tests/ui.spec.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/ui.spec.ts b/tests/ui.spec.ts index 81f6834f3..62bb4c6cb 100644 --- a/tests/ui.spec.ts +++ b/tests/ui.spec.ts @@ -1,6 +1,6 @@ import { test, expect } from 'playwright-test-coverage'; -test('history, about', async ({ page }) => { +test('history, about, docs', async ({ page }) => { await page.goto('/'); // About await page.getByRole('link', { name: 'About' }).click(); @@ -11,4 +11,8 @@ test('history, about', async ({ page }) => { await page.getByRole('link', { name: 'History' }).click(); await expect(page.getByText('Mama Rucci, my my')).toBeVisible(); await expect(page.getByRole('main').getByRole('img')).toBeVisible(); + + // Docs + await page.goto('/docs'); + await expect(page.getByText('JWT Pizza API')).toBeVisible(); }); From c986538849eb22657b02452ec0324cfa5242fa22 Mon Sep 17 00:00:00 2001 From: cjmot <146262493+cjmot@users.noreply.github.com> Date: Tue, 10 Feb 2026 11:46:08 -0700 Subject: [PATCH 21/42] add register test --- tests/auth.spec.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/auth.spec.ts b/tests/auth.spec.ts index 9bb17f7fe..6fc44b89b 100644 --- a/tests/auth.spec.ts +++ b/tests/auth.spec.ts @@ -48,3 +48,21 @@ test('purchase with login', async ({ page }) => { // Check balance await expect(page.getByText('0.008')).toBeVisible(); }); + +test('register', async ({ page }) => { + await basicInit(page); + + // Register new user + await page.getByRole('link', { name: 'Register' }).click(); + await expect(page.getByText('Welcome to the party')).toBeVisible(); + await page.getByPlaceholder('Full name').fill('New Name'); + await page.getByPlaceholder('Email address').fill('newEmail@test.com'); + await page.getByPlaceholder('Password').fill('newPassword'); + await page.getByRole('button', { name: 'Register' }).click(); + + // Diner Dashboard + await page.getByRole('link', { name: 'NN' }).click(); + await expect(page.getByText('New Name')).toBeVisible(); + await expect(page.getByText('newEmail@test.com')).toBeVisible(); + await expect(page.getByText('diner', { exact: true })).toBeVisible(); +}); From 85e19a65aa146f90c0fc73b3047c8f1f49036ffe Mon Sep 17 00:00:00 2001 From: cjmot <146262493+cjmot@users.noreply.github.com> Date: Tue, 10 Feb 2026 11:48:13 -0700 Subject: [PATCH 22/42] add register test --- tests/auth.spec.ts | 18 ++++++++++++++++++ tests/helpers.ts | 45 +++++++++++++++++++++++++++------------------ 2 files changed, 45 insertions(+), 18 deletions(-) diff --git a/tests/auth.spec.ts b/tests/auth.spec.ts index 9bb17f7fe..6fc44b89b 100644 --- a/tests/auth.spec.ts +++ b/tests/auth.spec.ts @@ -48,3 +48,21 @@ test('purchase with login', async ({ page }) => { // Check balance await expect(page.getByText('0.008')).toBeVisible(); }); + +test('register', async ({ page }) => { + await basicInit(page); + + // Register new user + await page.getByRole('link', { name: 'Register' }).click(); + await expect(page.getByText('Welcome to the party')).toBeVisible(); + await page.getByPlaceholder('Full name').fill('New Name'); + await page.getByPlaceholder('Email address').fill('newEmail@test.com'); + await page.getByPlaceholder('Password').fill('newPassword'); + await page.getByRole('button', { name: 'Register' }).click(); + + // Diner Dashboard + await page.getByRole('link', { name: 'NN' }).click(); + await expect(page.getByText('New Name')).toBeVisible(); + await expect(page.getByText('newEmail@test.com')).toBeVisible(); + await expect(page.getByText('diner', { exact: true })).toBeVisible(); +}); diff --git a/tests/helpers.ts b/tests/helpers.ts index 1bad951d4..90cdadd4a 100644 --- a/tests/helpers.ts +++ b/tests/helpers.ts @@ -65,19 +65,27 @@ async function basicInit(page: Page) { await route.fulfill({ json: { message: 'logged out successfully' } }); return; } - const loginReq = route.request().postDataJSON(); - const user = validUsers[loginReq.email]; - if (!user || user.password !== loginReq.password) { - await route.fulfill({ status: 401, json: { error: 'Unauthorized' } }); + const req = route.request().postDataJSON(); + if (route.request().method() === 'PUT') { + const user = validUsers[req.email]; + if (!user || user.password !== req.password) { + await route.fulfill({ status: 401, json: { error: 'Unauthorized' } }); + return; + } + loggedInUser = validUsers[req.email]; + const loginRes = { + user: loggedInUser, + token: 'abcdef', + }; + expect(route.request().method()).toBe('PUT'); + await route.fulfill({ json: loginRes }); return; } - loggedInUser = validUsers[loginReq.email]; - const loginRes = { - user: loggedInUser, - token: 'abcdef', - }; - expect(route.request().method()).toBe('PUT'); - await route.fulfill({ json: loginRes }); + const newUser = { ...req, id: '15', roles: [{ role: Role.Diner }] }; + validUsers[req.email] = newUser; + delete newUser.password; + loggedInUser = newUser; + await route.fulfill({ json: { user: newUser, token: 'abcdef' } }); }); // Return the currently logged in user @@ -161,13 +169,14 @@ async function basicInit(page: Page) { // Order a pizza. await page.route('*/**/api/order', async (route) => { - const orderReq = route.request().postDataJSON(); - const orderRes = { - order: { ...orderReq, id: 23 }, - jwt: 'eyJpYXQ', - }; - expect(route.request().method()).toBe('POST'); - await route.fulfill({ json: orderRes }); + if (route.request().method() === 'POST') { + const orderReq = route.request().postDataJSON(); + const orderRes = { + order: { ...orderReq, id: 23 }, + jwt: 'eyJpYXQ', + }; + await route.fulfill({ json: orderRes }); + } }); // Delete and Create store From 2cd2dd836318c3e6b6d1821b07b6885a4df6b197 Mon Sep 17 00:00:00 2001 From: cjmot <146262493+cjmot@users.noreply.github.com> Date: Tue, 10 Feb 2026 11:51:11 -0700 Subject: [PATCH 23/42] update coverage badge in README.md --- README.md | 70 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 38 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index fa5d4ec89..48865847a 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,14 @@ # 🍕 JWT Pizza -![Coverage badge](https://pizza-factory.cs329.click/api/badge/YOURNETID/jwtpizzacoverage)
+![Coverage badge](https://pizza-factory.cs329.click/api/badge/cjmotyer/jwtpizzacoverage)
[![CI Pipeline](https://github.com/cjmot/jwt-pizza/actions/workflows/ci.yml/badge.svg)](https://github.com/cjmot/jwt-pizza/actions/workflows/ci.yml) +A JSON Web Token, or [JWT](https://jwt.io/introduction), (pronounced JOT) is a digitally signed transfer of information +using JSON notation. Because you can validate the digital signature you can buy JWT pizzas with confidence. -A JSON Web Token, or [JWT](https://jwt.io/introduction), (pronounced JOT) is a digitally signed transfer of information using JSON notation. Because you can validate the digital signature you can buy JWT pizzas with confidence. - -`JWT Pizza` takes the next stage of digital evolution by allowing you to buy pizzas that you can never actually eat. Not only does JWT exchange bitcoin and give you nothing in return, it also allows for you to be come a franchisee and turn the whole vapor company into an MLM. +`JWT Pizza` takes the next stage of digital evolution by allowing you to buy pizzas that you can never actually eat. Not +only does JWT exchange bitcoin and give you nothing in return, it also allows for you to be come a franchisee and turn +the whole vapor company into an MLM. You can see a working example of the application at [pizza.cs329.click](https://pizza.cs329.click) @@ -32,7 +34,8 @@ You can see a working example of the application at [pizza.cs329.click](https:// ## Development notes -JWT Pizza uses Vite, React, Tailwind, and Preline. The following contains some notes about how these components were integrated into the project. +JWT Pizza uses Vite, React, Tailwind, and Preline. The following contains some notes about how these components were +integrated into the project. ### Vite @@ -47,15 +50,16 @@ Modify `package.json` ```json "scripts": { - "dev": "vite", - "build": "vite build", - "preview": "vite preview" - }, +"dev": "vite", +"build": "vite build", +"preview": "vite preview" +}, ``` ### React -React works out of the box with Vite, but we do need to install the desired React packages. The `index.html` file loads `index.jsx` which then loads the app component (`src/app.jsx`). +React works out of the box with Vite, but we do need to install the desired React packages. The `index.html` file loads +`index.jsx` which then loads the app component (`src/app.jsx`). ```sh npm install react react-dom react-router-dom @@ -75,11 +79,11 @@ Modify `tailwind.config.js` ```js /** @type {import('tailwindcss').Config} */ module.exports = { - content: ['index.html', './src/**/*.{html,js,jsx}'], - theme: { - extend: {}, - }, - plugins: [], + content: ['index.html', './src/**/*.{html,js,jsx}'], + theme: { + extend: {}, + }, + plugins: [], }; ``` @@ -94,9 +98,10 @@ Create a `main.css` and add the basic Tailwind directives. Modify `index.html` to include tailwind output.css. ```html + - ... - + ... + ``` @@ -104,7 +109,8 @@ Now when you run with `npm run dev` the css will automatically be generated. ### Preline -Added the Tailwind [Preline component library](https://preline.co/) so that I can use all of their nifty nav, slideshow, containers, and cards. +Added the Tailwind [Preline component library](https://preline.co/) so that I can use all of their nifty nav, slideshow, +containers, and cards. ```sh npm i preline @@ -116,15 +122,15 @@ Updated the tailwind config to use preline. const defaultTheme = require('tailwindcss/defaultTheme'); module.exports = { - content: ['index.html', './src/**/*.{html,js,jsx}', './node_modules/preline/preline.js'], - theme: { - extend: { - fontFamily: { - sans: ['Inter var', ...defaultTheme.fontFamily.sans], - }, + content: ['index.html', './src/**/*.{html,js,jsx}', './node_modules/preline/preline.js'], + theme: { + extend: { + fontFamily: { + sans: ['Inter var', ...defaultTheme.fontFamily.sans], + }, + }, }, - }, - plugins: [require('preline/plugin')], + plugins: [require('preline/plugin')], }; ``` @@ -137,15 +143,15 @@ import 'preline/preline'; Initialize components whenever the page location changes. ```js -import { useLocation, Routes, Route, NavLink } from 'react-router-dom'; +import {useLocation, Routes, Route, NavLink} from 'react-router-dom'; export default function App() { - const location = useLocation(); + const location = useLocation(); - useEffect(() => { - window.HSStaticMethods.autoInit(); - }, [location.pathname]); - //... + useEffect(() => { + window.HSStaticMethods.autoInit(); + }, [location.pathname]); +//... ``` ### Icons From ca8f5351cbaba7399137875991c368ffba139de7 Mon Sep 17 00:00:00 2001 From: Cooper Motyer <146262493+cjmot@users.noreply.github.com> Date: Tue, 10 Feb 2026 12:00:39 -0700 Subject: [PATCH 24/42] Update README.md From 218c2984e810e0ba912884c06fe1e6e6365cc4e0 Mon Sep 17 00:00:00 2001 From: cjmot <146262493+cjmot@users.noreply.github.com> Date: Tue, 10 Feb 2026 12:15:43 -0700 Subject: [PATCH 25/42] prettier reformat --- src/app/app.tsx | 183 ++++++++------ src/app/footer.tsx | 57 ++--- src/app/header.tsx | 130 +++++----- src/components/breadcrumb.tsx | 60 +++-- src/components/button.tsx | 27 ++- src/components/card.tsx | 41 ++-- src/components/carousel.tsx | 44 ++-- src/components/quote.tsx | 54 +++-- src/hooks/appNavigation.tsx | 24 +- src/service/httpPizzaService.ts | 212 +++++++++-------- src/service/pizzaService.ts | 148 +++++++----- src/views/about.tsx | 194 ++++++++------- src/views/adminDashboard.tsx | 298 ++++++++++++++--------- src/views/closeFranchise.tsx | 42 ++-- src/views/closeStore.tsx | 42 ++-- src/views/createFranchise.tsx | 99 ++++---- src/views/createStore.tsx | 72 +++--- src/views/delivery.tsx | 187 +++++++++------ src/views/dinerDashboard.tsx | 202 +++++++++------- src/views/docs.tsx | 82 ++++--- src/views/franchiseDashboard.tsx | 395 ++++++++++++++++++------------- src/views/history.tsx | 66 ++++-- src/views/home.tsx | 125 ++++++---- src/views/login.tsx | 177 +++++++------- src/views/logout.tsx | 24 +- src/views/menu.tsx | 159 ++++++++----- src/views/notFound.tsx | 12 +- src/views/payment.tsx | 180 ++++++++------ src/views/register.tsx | 209 ++++++++-------- src/views/view.tsx | 34 +-- 30 files changed, 2052 insertions(+), 1527 deletions(-) diff --git a/src/app/app.tsx b/src/app/app.tsx index 083353ae3..83bc3c092 100644 --- a/src/app/app.tsx +++ b/src/app/app.tsx @@ -27,81 +27,130 @@ import { Role, User } from '../service/pizzaService'; import 'preline/preline'; declare global { - interface Window { - HSStaticMethods: any; - } + interface Window { + HSStaticMethods: any; + } } export default function App() { - const [user, setUser] = React.useState(null); - const location = useLocation(); + const [user, setUser] = React.useState(null); + const location = useLocation(); - useEffect(() => { - (async () => { - const user = await pizzaService.getUser(); - setUser(user); - })(); - }, []); + useEffect(() => { + (async () => { + const user = await pizzaService.getUser(); + setUser(user); + })(); + }, []); - useEffect(() => { - window.HSStaticMethods.autoInit(); - window.scrollTo(0, 0); - }, [location.pathname]); + useEffect(() => { + window.HSStaticMethods.autoInit(); + window.scrollTo(0, 0); + }, [location.pathname]); - function loggedIn() { - return !!user; - } - function loggedOut() { - return !loggedIn(); - } - function isAdmin() { - return Role.isRole(user, Role.Admin); - } - function isNotAdmin() { - return !isAdmin(); - } + function loggedIn() { + return !!user; + } + function loggedOut() { + return !loggedIn(); + } + function isAdmin() { + return Role.isRole(user, Role.Admin); + } + function isNotAdmin() { + return !isAdmin(); + } - const navItems = [ - { title: 'Home', to: '/', component: , display: [] }, - { title: 'Diner', to: '/diner-dashboard', component: , display: [] }, - { title: 'Order', to: '/menu', component: , display: ['nav'] }, - { - title: 'Franchise', - to: '/franchise-dashboard', - component: , - constraints: [isNotAdmin], - display: ['nav', 'footer'], - }, - { title: 'About', to: '/about', component: , display: ['footer'] }, - { title: 'History', to: '/history', component: , display: ['footer'] }, - { title: 'Admin', to: '/admin-dashboard', component: , constraints: [isAdmin], display: ['nav'] }, - { title: 'Create franchise', to: '/:subPath?/create-franchise', component: , display: [] }, - { title: 'Close franchise', to: '/:subPath?/close-franchise', component: , display: [] }, - { title: 'Create store', to: '/:subPath?/create-store', component: , display: [] }, - { title: 'Close store', to: '/:subPath?/close-store', component: , display: [] }, - { title: 'Payment', to: '/payment', component: , display: [] }, - { title: 'Delivery', to: '/delivery', component: , display: [] }, - { title: 'Login', to: '/:subPath?/login', component: , constraints: [loggedOut], display: ['nav'] }, - { title: 'Register', to: '/:subPath?/register', component: , constraints: [loggedOut], display: ['nav'] }, - { title: 'Logout', to: '/:subPath?/logout', component: , constraints: [loggedIn], display: ['nav'] }, - { title: 'Docs', to: '/docs/:docType?', component: , display: [] }, - { title: 'Opps', to: '*', component: , display: [] }, - ]; + const navItems = [ + { title: 'Home', to: '/', component: , display: [] }, + { + title: 'Diner', + to: '/diner-dashboard', + component: , + display: [], + }, + { title: 'Order', to: '/menu', component: , display: ['nav'] }, + { + title: 'Franchise', + to: '/franchise-dashboard', + component: , + constraints: [isNotAdmin], + display: ['nav', 'footer'], + }, + { title: 'About', to: '/about', component: , display: ['footer'] }, + { title: 'History', to: '/history', component: , display: ['footer'] }, + { + title: 'Admin', + to: '/admin-dashboard', + component: , + constraints: [isAdmin], + display: ['nav'], + }, + { + title: 'Create franchise', + to: '/:subPath?/create-franchise', + component: , + display: [], + }, + { + title: 'Close franchise', + to: '/:subPath?/close-franchise', + component: , + display: [], + }, + { + title: 'Create store', + to: '/:subPath?/create-store', + component: , + display: [], + }, + { + title: 'Close store', + to: '/:subPath?/close-store', + component: , + display: [], + }, + { title: 'Payment', to: '/payment', component: , display: [] }, + { title: 'Delivery', to: '/delivery', component: , display: [] }, + { + title: 'Login', + to: '/:subPath?/login', + component: , + constraints: [loggedOut], + display: ['nav'], + }, + { + title: 'Register', + to: '/:subPath?/register', + component: , + constraints: [loggedOut], + display: ['nav'], + }, + { + title: 'Logout', + to: '/:subPath?/logout', + component: , + constraints: [loggedIn], + display: ['nav'], + }, + { title: 'Docs', to: '/docs/:docType?', component: , display: [] }, + { title: 'Opps', to: '*', component: , display: [] }, + ]; - return ( -
-
- + return ( +
+
+ -
- - {navItems.map((item) => ( - - ))} - -
+
+ + {navItems.map((item) => ( + + ))} + +
-
-
- ); +
+
+ ); } diff --git a/src/app/footer.tsx b/src/app/footer.tsx index 369eeb867..49eb86501 100644 --- a/src/app/footer.tsx +++ b/src/app/footer.tsx @@ -2,36 +2,39 @@ import React from 'react'; import { NavLink } from 'react-router-dom'; interface Props { - navItems: { title: string; to: string; display: string[] }[]; + navItems: { title: string; to: string; display: string[] }[]; } export default function Footer(props: Props) { - const [version, setVersion] = React.useState(''); + const [version, setVersion] = React.useState(''); - React.useEffect(() => { - fetch('/version.json') - .then((response) => response.json()) - .then((data) => setVersion(data.version)); - }, []); + React.useEffect(() => { + fetch('/version.json') + .then((response) => response.json()) + .then((data) => setVersion(data.version)); + }, []); - return ( -
-
- -

© 2024 JWT Pizza LTD. All rights reserved. Version: {version}

-
-
- ); + return ( +
+
+ +

+ © 2024 JWT Pizza LTD. All rights reserved. Version: {version} +

+
+
+ ); } diff --git a/src/app/header.tsx b/src/app/header.tsx index 511fc1312..eced6e14a 100644 --- a/src/app/header.tsx +++ b/src/app/header.tsx @@ -4,65 +4,83 @@ import { HamburgerIcon, CloseIcon } from '../icons'; import { User } from '../service/pizzaService'; interface Props { - user: User | null; - navItems: { title: string; to: string; display: string[]; constraints?: (() => boolean)[] }[]; + user: User | null; + navItems: { title: string; to: string; display: string[]; constraints?: (() => boolean)[] }[]; } export default function Header(props: Props) { - function validateConstraints(constraints: (() => boolean)[]) { - return constraints.every((c) => c()); - } + function validateConstraints(constraints: (() => boolean)[]) { + return constraints.every((c) => c()); + } - function generateUserText(user: User) { - const names = user?.name?.split(' ') || ['?']; - return names.length > 1 ? names[0].charAt(0) + names[names.length - 1].charAt(0) : names[0].charAt(0); - } + function generateUserText(user: User) { + const names = user?.name?.split(' ') || ['?']; + return names.length > 1 + ? names[0].charAt(0) + names[names.length - 1].charAt(0) + : names[0].charAt(0); + } - return ( -
-
- -
-
- ); + return ( +
+
+ +
+
+ ); } diff --git a/src/components/breadcrumb.tsx b/src/components/breadcrumb.tsx index 5baf80fea..3372084ec 100644 --- a/src/components/breadcrumb.tsx +++ b/src/components/breadcrumb.tsx @@ -3,34 +3,44 @@ import { NavLink } from 'react-router-dom'; import { HouseIcon, GreaterThanIcon } from '../icons'; interface Props { - location: string; + location: string; } export default function Breadcrumb(props: Props) { - let currentPath = ''; - const paths = props.location.split('/').map((path) => { - currentPath += '/' + path; - return ( -
  • - + let currentPath = ''; + const paths = props.location.split('/').map((path) => { + currentPath += '/' + path; + return ( +
  • + - - {path} - -
  • + + {path} + + + ); + }); + return ( +
      +
    1. + + + + + home + +
    2. + {location && paths} +
    ); - }); - return ( -
      -
    1. - - - - - home - -
    2. - {location && paths} -
    - ); } diff --git a/src/components/button.tsx b/src/components/button.tsx index 30c237eac..2cbd43ac1 100644 --- a/src/components/button.tsx +++ b/src/components/button.tsx @@ -1,18 +1,23 @@ import React from 'react'; interface Props { - title: string; - onPress: () => void; - disabled?: boolean; - submit?: boolean; - className?: string; + title: string; + onPress: () => void; + disabled?: boolean; + submit?: boolean; + className?: string; } export default function Button(props: Props) { - const finalClassName = `w-32 m-4 py-3 px-4 text-sm font-semibold rounded-lg border border-transparent bg-orange-800 text-white hover:bg-orange-600 ${props.className}`; - return ( - - ); + const finalClassName = `w-32 m-4 py-3 px-4 text-sm font-semibold rounded-lg border border-transparent bg-orange-800 text-white hover:bg-orange-600 ${props.className}`; + return ( + + ); } diff --git a/src/components/card.tsx b/src/components/card.tsx index d5c1e4129..5cda4013d 100644 --- a/src/components/card.tsx +++ b/src/components/card.tsx @@ -1,27 +1,30 @@ import React from 'react'; interface Props { - title: string; - description: string; - image: string; + title: string; + description: string; + image: string; } export default function Card(props: Props) { - return ( -
    - - - ); + ); } diff --git a/src/components/carousel.tsx b/src/components/carousel.tsx index 62094e11a..41f4b233d 100644 --- a/src/components/carousel.tsx +++ b/src/components/carousel.tsx @@ -1,29 +1,33 @@ import React from 'react'; interface Props { - slides: React.ReactNode[]; + slides: React.ReactNode[]; } export default function Carousel(props: Props) { - return ( -
    -
    -
    - {props.slides.map((slide, index) => ( -
    - {slide} + return ( +
    +
    +
    + {props.slides.map((slide, index) => ( +
    + {slide} +
    + ))} +
    - ))} -
    -
    -
    - {props.slides.map((_, index) => ( - - ))} -
    -
    - ); +
    + {props.slides.map((_, index) => ( + + ))} +
    +
    + ); } diff --git a/src/components/quote.tsx b/src/components/quote.tsx index c7fa1a9f1..b67898d1b 100644 --- a/src/components/quote.tsx +++ b/src/components/quote.tsx @@ -1,34 +1,36 @@ import React from 'react'; interface Props { - quote: string; - author: string; + quote: string; + author: string; } export default function Quote(props: Props) { - return ( -
    - + return ( +
    + -
    -

    - - {props.quote} - — {props.author} - -

    -
    -
    - ); +
    +

    + + {props.quote} + — {props.author} + +

    +
    +
    + ); } diff --git a/src/hooks/appNavigation.tsx b/src/hooks/appNavigation.tsx index 4b3ac4982..5f3bf8c50 100644 --- a/src/hooks/appNavigation.tsx +++ b/src/hooks/appNavigation.tsx @@ -1,20 +1,20 @@ import { useLocation, useNavigate } from 'react-router-dom'; function useBreadcrumb(sibling?: string) { - const location = useLocation(); - const navigate = useNavigate(); + const location = useLocation(); + const navigate = useNavigate(); - const navigateByBreadcrumb = () => { - let newPath = location.pathname.substring(0, location.pathname.lastIndexOf('/')); - if (sibling) { - newPath = newPath + '/' + sibling; - } else if (newPath === '') { - newPath = '/'; - } - navigate(newPath, { state: location.state }); - }; + const navigateByBreadcrumb = () => { + let newPath = location.pathname.substring(0, location.pathname.lastIndexOf('/')); + if (sibling) { + newPath = newPath + '/' + sibling; + } else if (newPath === '') { + newPath = '/'; + } + navigate(newPath, { state: location.state }); + }; - return navigateByBreadcrumb; + return navigateByBreadcrumb; } export { useBreadcrumb }; diff --git a/src/service/httpPizzaService.ts b/src/service/httpPizzaService.ts index 12ffbdb49..040a39790 100644 --- a/src/service/httpPizzaService.ts +++ b/src/service/httpPizzaService.ts @@ -1,121 +1,141 @@ -import { PizzaService, Franchise, FranchiseList, Store, OrderHistory, User, Menu, Order, Endpoints, OrderResponse, JWTPayload } from './pizzaService'; +import { + PizzaService, + Franchise, + FranchiseList, + Store, + OrderHistory, + User, + Menu, + Order, + Endpoints, + OrderResponse, + JWTPayload, +} from './pizzaService'; const pizzaServiceUrl = import.meta.env.VITE_PIZZA_SERVICE_URL; const pizzaFactoryUrl = import.meta.env.VITE_PIZZA_FACTORY_URL; class HttpPizzaService implements PizzaService { - async callEndpoint(path: string, method: string = 'GET', body?: any): Promise { - return new Promise(async (resolve, reject) => { - try { - const options: any = { - method: method, - headers: { - 'Content-Type': 'application/json', - }, - credentials: 'include', - }; - - const authToken = localStorage.getItem('token'); - if (authToken) { - options.headers['Authorization'] = `Bearer ${authToken}`; - } + async callEndpoint(path: string, method: string = 'GET', body?: any): Promise { + return new Promise(async (resolve, reject) => { + try { + const options: any = { + method: method, + headers: { + 'Content-Type': 'application/json', + }, + credentials: 'include', + }; + + const authToken = localStorage.getItem('token'); + if (authToken) { + options.headers['Authorization'] = `Bearer ${authToken}`; + } + + if (body) { + options.body = JSON.stringify(body); + } + + if (!path.startsWith('http')) { + path = pizzaServiceUrl + path; + } + + const r = await fetch(path, options); + const j = await r.json(); + if (r.ok) { + resolve(j); + } else { + reject({ code: r.status, message: j.message }); + } + } catch (e: any) { + reject({ code: 500, message: e.message }); + } + }); + } - if (body) { - options.body = JSON.stringify(body); - } + async login(email: string, password: string): Promise { + const { user, token } = await this.callEndpoint('/api/auth', 'PUT', { email, password }); + localStorage.setItem('token', token); + return Promise.resolve(user); + } - if (!path.startsWith('http')) { - path = pizzaServiceUrl + path; - } + async register(name: string, email: string, password: string): Promise { + const { user, token } = await this.callEndpoint('/api/auth', 'POST', { + name, + email, + password, + }); + localStorage.setItem('token', token); + return Promise.resolve(user); + } - const r = await fetch(path, options); - const j = await r.json(); - if (r.ok) { - resolve(j); - } else { - reject({ code: r.status, message: j.message }); - } - } catch (e: any) { - reject({ code: 500, message: e.message }); - } - }); - } - - async login(email: string, password: string): Promise { - const { user, token } = await this.callEndpoint('/api/auth', 'PUT', { email, password }); - localStorage.setItem('token', token); - return Promise.resolve(user); - } - - async register(name: string, email: string, password: string): Promise { - const { user, token } = await this.callEndpoint('/api/auth', 'POST', { name, email, password }); - localStorage.setItem('token', token); - return Promise.resolve(user); - } - - logout(): void { - this.callEndpoint('/api/auth', 'DELETE'); - localStorage.removeItem('token'); - } - - async getUser(): Promise { - let result: User | null = null; - if (localStorage.getItem('token')) { - try { - result = await this.callEndpoint('/api/user/me'); - } catch (e) { + logout(): void { + this.callEndpoint('/api/auth', 'DELETE'); localStorage.removeItem('token'); - } } - return Promise.resolve(result); - } - async getMenu(): Promise { - return this.callEndpoint('/api/order/menu'); - } + async getUser(): Promise { + let result: User | null = null; + if (localStorage.getItem('token')) { + try { + result = await this.callEndpoint('/api/user/me'); + } catch (e) { + localStorage.removeItem('token'); + } + } + return Promise.resolve(result); + } - async getOrders(user: User): Promise { - return this.callEndpoint('/api/order'); - } + async getMenu(): Promise { + return this.callEndpoint('/api/order/menu'); + } - async order(order: Order): Promise { - return this.callEndpoint('/api/order', 'POST', order); - } + async getOrders(user: User): Promise { + return this.callEndpoint('/api/order'); + } - async verifyOrder(jwt: string): Promise { - return this.callEndpoint(pizzaFactoryUrl + '/api/order/verify', 'POST', { jwt }); - } + async order(order: Order): Promise { + return this.callEndpoint('/api/order', 'POST', order); + } - async getFranchise(user: User): Promise { - return this.callEndpoint(`/api/franchise/${user.id}`); - } + async verifyOrder(jwt: string): Promise { + return this.callEndpoint(pizzaFactoryUrl + '/api/order/verify', 'POST', { jwt }); + } - async createFranchise(franchise: Franchise): Promise { - return this.callEndpoint('/api/franchise', 'POST', franchise); - } + async getFranchise(user: User): Promise { + return this.callEndpoint(`/api/franchise/${user.id}`); + } + + async createFranchise(franchise: Franchise): Promise { + return this.callEndpoint('/api/franchise', 'POST', franchise); + } - async getFranchises(page: number = 0, limit: number = 10, nameFilter: string = '*'): Promise { - return this.callEndpoint(`/api/franchise?page=${page}&limit=${limit}&name=${nameFilter}`); - } + async getFranchises( + page: number = 0, + limit: number = 10, + nameFilter: string = '*', + ): Promise { + return this.callEndpoint(`/api/franchise?page=${page}&limit=${limit}&name=${nameFilter}`); + } - async closeFranchise(franchise: Franchise): Promise { - return this.callEndpoint(`/api/franchise/${franchise.id}`, 'DELETE'); - } + async closeFranchise(franchise: Franchise): Promise { + return this.callEndpoint(`/api/franchise/${franchise.id}`, 'DELETE'); + } - async createStore(franchise: Franchise, store: Store): Promise { - return this.callEndpoint(`/api/franchise/${franchise.id}/store`, 'POST', store); - } + async createStore(franchise: Franchise, store: Store): Promise { + return this.callEndpoint(`/api/franchise/${franchise.id}/store`, 'POST', store); + } - async closeStore(franchise: Franchise, store: Store): Promise { - return this.callEndpoint(`/api/franchise/${franchise.id}/store/${store.id}`, 'DELETE'); - } + async closeStore(franchise: Franchise, store: Store): Promise { + return this.callEndpoint(`/api/franchise/${franchise.id}/store/${store.id}`, 'DELETE'); + } - async docs(docType: string): Promise { - if (docType === 'factory') { - return this.callEndpoint(pizzaFactoryUrl + `/api/docs`); + async docs(docType: string): Promise { + if (docType === 'factory') { + return this.callEndpoint(pizzaFactoryUrl + `/api/docs`); + } + return this.callEndpoint(`/api/docs`); } - return this.callEndpoint(`/api/docs`); - } } const httpPizzaService = new HttpPizzaService(); diff --git a/src/service/pizzaService.ts b/src/service/pizzaService.ts index 60dae2604..6f38eb87d 100644 --- a/src/service/pizzaService.ts +++ b/src/service/pizzaService.ts @@ -1,115 +1,133 @@ enum Role { - Diner = 'diner', - Franchisee = 'franchisee', - Admin = 'admin', + Diner = 'diner', + Franchisee = 'franchisee', + Admin = 'admin', } namespace Role { - export function isRole(user: User | null, role: Role): boolean { - return user != null && Array.isArray(user.roles) && !!user.roles.find((r) => r.role === role); - } + export function isRole(user: User | null, role: Role): boolean { + return ( + user != null && Array.isArray(user.roles) && !!user.roles.find((r) => r.role === role) + ); + } } type Menu = Pizza[]; type Pizza = { - id: string; - title: string; - description: string; - image: string; - price: number; + id: string; + title: string; + description: string; + image: string; + price: number; }; type OrderItem = { - menuId: string; - description: string; - price: number; + menuId: string; + description: string; + price: number; }; type Order = { - id: string; - franchiseId: string; - storeId: string; - date: string; - items: OrderItem[]; + id: string; + franchiseId: string; + storeId: string; + date: string; + items: OrderItem[]; }; type OrderResponse = { - order: Order; - jwt: string; + order: Order; + jwt: string; }; type OrderHistory = { - id: string; - dinerId: string; - orders: Order[]; + id: string; + dinerId: string; + orders: Order[]; }; type UserRole = { - role: Role; - objectId?: string; + role: Role; + objectId?: string; }; type User = { - id?: string; - name?: string; - email?: string; - password?: string; - roles?: UserRole[]; + id?: string; + name?: string; + email?: string; + password?: string; + roles?: UserRole[]; }; type Store = { - id: string; - name: string; - totalRevenue?: number; + id: string; + name: string; + totalRevenue?: number; }; type Franchise = { - id: string; - admins?: { email: string; id?: string; name?: string }[]; - name: string; - stores: Store[]; + id: string; + admins?: { email: string; id?: string; name?: string }[]; + name: string; + stores: Store[]; }; type FranchiseList = { - franchises: Franchise[]; - more: boolean; + franchises: Franchise[]; + more: boolean; }; type Endpoint = { - requiresAuth: boolean; - method: string; - path: string; - description: string; - example: string; - response: any; + requiresAuth: boolean; + method: string; + path: string; + description: string; + example: string; + response: any; }; type Endpoints = { - endpoints: Endpoint[]; + endpoints: Endpoint[]; }; type JWTPayload = { - message: string; - payload: string; + message: string; + payload: string; }; interface PizzaService { - login(email: string, password: string): Promise; - register(email: string, password: string, role: string): Promise; - logout(): void; - getUser(): Promise; - getMenu(): Promise; - getOrders(user: User): Promise; - order(order: Order): Promise; - verifyOrder(jwt: string): Promise; - getFranchise(user: User): Promise; - createFranchise(franchise: Franchise): Promise; - getFranchises(page: number, limit: number, nameFilter: string): Promise; - closeFranchise(franchise: Franchise): Promise; - createStore(franchise: Franchise, store: Store): Promise; - closeStore(franchise: Franchise, store: Store): Promise; - docs(docType: string): Promise; + login(email: string, password: string): Promise; + register(email: string, password: string, role: string): Promise; + logout(): void; + getUser(): Promise; + getMenu(): Promise; + getOrders(user: User): Promise; + order(order: Order): Promise; + verifyOrder(jwt: string): Promise; + getFranchise(user: User): Promise; + createFranchise(franchise: Franchise): Promise; + getFranchises(page: number, limit: number, nameFilter: string): Promise; + closeFranchise(franchise: Franchise): Promise; + createStore(franchise: Franchise, store: Store): Promise; + closeStore(franchise: Franchise, store: Store): Promise; + docs(docType: string): Promise; } -export { Role, PizzaService, User, Menu, Pizza, OrderHistory, Order, Franchise, FranchiseList, Store, OrderItem, Endpoint, Endpoints, OrderResponse, JWTPayload }; +export { + Role, + PizzaService, + User, + Menu, + Pizza, + OrderHistory, + Order, + Franchise, + FranchiseList, + Store, + OrderItem, + Endpoint, + Endpoints, + OrderResponse, + JWTPayload, +}; diff --git a/src/views/about.tsx b/src/views/about.tsx index a38ee4e2c..1f2955131 100644 --- a/src/views/about.tsx +++ b/src/views/about.tsx @@ -2,92 +2,114 @@ import React from 'react'; import View from './view'; export default function About() { - return ( - -
    - -

    - At JWT Pizza, our amazing employees are the secret behind our delicious pizzas. They are passionate about their craft and spend every waking moment dreaming about how to make our pizzas even - better. From selecting the finest ingredients to perfecting the dough and sauce recipes, our employees go above and beyond to ensure the highest quality and taste in every bite. Their - dedication and attention to detail make all the difference in creating a truly exceptional pizza experience for our customers. We take pride in our team and their commitment to delivering - the best pizza in town. -

    -

    - Our talented employees at JWT Pizza are true artisans. They pour their heart and soul into every pizza they create, striving for perfection in every aspect. From hand-stretching the dough to - carefully layering the toppings, they take pride in their work and are constantly seeking ways to elevate the pizza-making process. Their creativity and expertise shine through in every - slice, resulting in a pizza that is not only delicious but also a work of art. We are grateful for our dedicated team and their unwavering commitment to delivering the most flavorful and - satisfying pizzas to our valued customers. -

    + return ( + +
    + +

    + At JWT Pizza, our amazing employees are the secret behind our delicious pizzas. + They are passionate about their craft and spend every waking moment dreaming + about how to make our pizzas even better. From selecting the finest ingredients + to perfecting the dough and sauce recipes, our employees go above and beyond to + ensure the highest quality and taste in every bite. Their dedication and + attention to detail make all the difference in creating a truly exceptional + pizza experience for our customers. We take pride in our team and their + commitment to delivering the best pizza in town. +

    +

    + Our talented employees at JWT Pizza are true artisans. They pour their heart and + soul into every pizza they create, striving for perfection in every aspect. From + hand-stretching the dough to carefully layering the toppings, they take pride in + their work and are constantly seeking ways to elevate the pizza-making process. + Their creativity and expertise shine through in every slice, resulting in a + pizza that is not only delicious but also a work of art. We are grateful for our + dedicated team and their unwavering commitment to delivering the most flavorful + and satisfying pizzas to our valued customers. +

    -

    Our employees

    +

    + Our employees +

    -

    - JWT Pizza is home to a team of pizza enthusiasts who are truly passionate about their craft. They are constantly experimenting with new flavors, techniques, and ingredients to push the - boundaries of traditional pizza-making. Their relentless pursuit of perfection is evident in every bite, as they strive to create a pizza experience that is unparalleled. Our employees - understand that the secret to a great pizza lies in the details, and they leave no stone unturned in their quest for pizza perfection. We are proud to have such dedicated individuals on our - team, as they are the driving force behind our reputation for exceptional quality and taste. -

    -
    -
    - Employee stock photo - - James - -
    -
    - Employee stock photo - - Maria - -
    -
    - Employee stock photo - - Anna - -
    -
    - Employee stock photo - - Brian - -
    -
    -

    - At JWT Pizza, our employees are more than just pizza makers. They are culinary artists who are deeply passionate about their craft. They approach each pizza with creativity, precision, and a - genuine love for what they do. From experimenting with unique flavor combinations to perfecting the cooking process, our employees are constantly pushing the boundaries of what a pizza can - be. Their dedication and expertise result in pizzas that are not only delicious but also a reflection of their passion and commitment. We are grateful for our talented team and the - incredible pizzas they create day in and day out. -

    -
    -
    - ); +

    + JWT Pizza is home to a team of pizza enthusiasts who are truly passionate about + their craft. They are constantly experimenting with new flavors, techniques, and + ingredients to push the boundaries of traditional pizza-making. Their relentless + pursuit of perfection is evident in every bite, as they strive to create a pizza + experience that is unparalleled. Our employees understand that the secret to a + great pizza lies in the details, and they leave no stone unturned in their quest + for pizza perfection. We are proud to have such dedicated individuals on our + team, as they are the driving force behind our reputation for exceptional + quality and taste. +

    +
    +
    + Employee stock photo + + James + +
    +
    + Employee stock photo + + Maria + +
    +
    + Employee stock photo + + Anna + +
    +
    + Employee stock photo + + Brian + +
    +
    +

    + At JWT Pizza, our employees are more than just pizza makers. They are culinary + artists who are deeply passionate about their craft. They approach each pizza + with creativity, precision, and a genuine love for what they do. From + experimenting with unique flavor combinations to perfecting the cooking process, + our employees are constantly pushing the boundaries of what a pizza can be. + Their dedication and expertise result in pizzas that are not only delicious but + also a reflection of their passion and commitment. We are grateful for our + talented team and the incredible pizzas they create day in and day out. +

    +
    +
    + ); } diff --git a/src/views/adminDashboard.tsx b/src/views/adminDashboard.tsx index d49e16e06..0726904b7 100644 --- a/src/views/adminDashboard.tsx +++ b/src/views/adminDashboard.tsx @@ -8,124 +8,206 @@ import { Franchise, FranchiseList, Role, Store, User } from '../service/pizzaSer import { TrashIcon } from '../icons'; interface Props { - user: User | null; + user: User | null; } export default function AdminDashboard(props: Props) { - const navigate = useNavigate(); - const [franchiseList, setFranchiseList] = React.useState({ franchises: [], more: false }); - const [franchisePage, setFranchisePage] = React.useState(0); - const filterFranchiseRef = React.useRef(null); + const navigate = useNavigate(); + const [franchiseList, setFranchiseList] = React.useState({ + franchises: [], + more: false, + }); + const [franchisePage, setFranchisePage] = React.useState(0); + const filterFranchiseRef = React.useRef(null); - React.useEffect(() => { - (async () => { - setFranchiseList(await pizzaService.getFranchises(franchisePage, 3, '*')); - })(); - }, [props.user, franchisePage]); + React.useEffect(() => { + (async () => { + setFranchiseList(await pizzaService.getFranchises(franchisePage, 3, '*')); + })(); + }, [props.user, franchisePage]); - function createFranchise() { - navigate('/admin-dashboard/create-franchise'); - } + function createFranchise() { + navigate('/admin-dashboard/create-franchise'); + } - async function closeFranchise(franchise: Franchise) { - navigate('/admin-dashboard/close-franchise', { state: { franchise: franchise } }); - } + async function closeFranchise(franchise: Franchise) { + navigate('/admin-dashboard/close-franchise', { state: { franchise: franchise } }); + } - async function closeStore(franchise: Franchise, store: Store) { - navigate('/admin-dashboard/close-store', { state: { franchise: franchise, store: store } }); - } + async function closeStore(franchise: Franchise, store: Store) { + navigate('/admin-dashboard/close-store', { state: { franchise: franchise, store: store } }); + } - async function filterFranchises() { - setFranchiseList(await pizzaService.getFranchises(franchisePage, 10, `*${filterFranchiseRef.current?.value}*`)); - } + async function filterFranchises() { + setFranchiseList( + await pizzaService.getFranchises( + franchisePage, + 10, + `*${filterFranchiseRef.current?.value}*`, + ), + ); + } - let response = ; - if (Role.isRole(props.user, Role.Admin)) { - response = ( - -
    -

    Franchises

    -
    -
    -
    -
    -
    - - - - {['Franchise', 'Franchisee', 'Store', 'Revenue', 'Action'].map((header) => ( - - ))} - - - {franchiseList.franchises.map((franchise, findex) => { - return ( - - - - - - + let response = ; + if (Role.isRole(props.user, Role.Admin)) { + response = ( + +
    +

    Franchises

    +
    +
    +
    +
    +
    +
    - {header} -
    {franchise.name} - {franchise.admins?.map((o) => o.name).join(', ')} - - -
    + + + {[ + 'Franchise', + 'Franchisee', + 'Store', + 'Revenue', + 'Action', + ].map((header) => ( + + ))} + + + {franchiseList.franchises.map((franchise, findex) => { + return ( + + + + + + - {franchise.stores.map((store, sindex) => { - return ( - - - - - - ); - })} - - ); - })} - - - - - - -
    + {header} +
    + {franchise.name} + + {franchise.admins + ?.map((o) => o.name) + .join(', ')} + + +
    - {store.name} - {store.totalRevenue?.toLocaleString()} ₿ - -
    - - - - - -
    -
    + {franchise.stores.map((store, sindex) => { + return ( + + + {store.name} + + + {store.totalRevenue?.toLocaleString()}{' '} + ₿ + + + + + + ); + })} + + ); + })} + + + + + + + + + + + + + +
    +
    +
    +
    +
    -
    - - - -
    -
    - - ); - } +
    +
    + + ); + } - return response; + return response; } diff --git a/src/views/closeFranchise.tsx b/src/views/closeFranchise.tsx index 2a7029f68..73853e2c6 100644 --- a/src/views/closeFranchise.tsx +++ b/src/views/closeFranchise.tsx @@ -6,24 +6,30 @@ import Button from '../components/button'; import { useBreadcrumb } from '../hooks/appNavigation'; export default function CloseFranchise() { - const state = useLocation().state; - const navigateToParentPath = useBreadcrumb(); + const state = useLocation().state; + const navigateToParentPath = useBreadcrumb(); - async function close() { - await pizzaService.closeFranchise(state.franchise); - navigateToParentPath(); - } + async function close() { + await pizzaService.closeFranchise(state.franchise); + navigateToParentPath(); + } - return ( - -
    -
    - Are you sure you want to close the {state.franchise.name} franchise? This will close all associated stores and cannot be restored. All outstanding - revenue will not be refunded. -
    -
    -
    - ); + return ( + +
    +
    + Are you sure you want to close the{' '} + {state.franchise.name} franchise? This + will close all associated stores and cannot be restored. All outstanding revenue + will not be refunded. +
    +
    +
    + ); } diff --git a/src/views/closeStore.tsx b/src/views/closeStore.tsx index 5e78b1796..22ef619d1 100644 --- a/src/views/closeStore.tsx +++ b/src/views/closeStore.tsx @@ -6,24 +6,30 @@ import View from './view'; import Button from '../components/button'; export default function CloseStore() { - const state = useLocation().state; - const navigateToParent = useBreadcrumb(); + const state = useLocation().state; + const navigateToParent = useBreadcrumb(); - async function close() { - await pizzaService.closeStore(state.franchise, state.store); - navigateToParent(); - } + async function close() { + await pizzaService.closeStore(state.franchise, state.store); + navigateToParent(); + } - return ( - -
    -
    - Are you sure you want to close the {state.franchise.name} store {state.store.name} ? This cannot be - restored. All outstanding revenue will not be refunded. -
    -
    -
    - ); + return ( + +
    +
    + Are you sure you want to close the{' '} + {state.franchise.name} store{' '} + {state.store.name} ? This cannot be + restored. All outstanding revenue will not be refunded. +
    +
    +
    + ); } diff --git a/src/views/createFranchise.tsx b/src/views/createFranchise.tsx index daa0440fa..e19b6826e 100644 --- a/src/views/createFranchise.tsx +++ b/src/views/createFranchise.tsx @@ -8,51 +8,62 @@ import Button from '../components/button'; import { Franchise } from '../service/pizzaService'; export default function CreateFranchise() { - const navigateToParentPath = useBreadcrumb(); - const [franchise, setFranchise] = React.useState({ stores: [], id: '', name: '' }); + const navigateToParentPath = useBreadcrumb(); + const [franchise, setFranchise] = React.useState({ stores: [], id: '', name: '' }); - async function createFranchise(event: React.FormEvent) { - event.preventDefault(); - await pizzaService.createFranchise(franchise); - navigateToParentPath(); - } + async function createFranchise(event: React.FormEvent) { + event.preventDefault(); + await pizzaService.createFranchise(franchise); + navigateToParentPath(); + } - return ( - -
    -
    -
    Want to create franchise?
    -
    -
    - setFranchise({ ...franchise, name: e.target.value })} - className="peer py-3 px-4 ps-11 block w-full bg-gray-100 border-transparent rounded-lg text-sm focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none" - placeholder="franchise name" - /> -
    - -
    -
    -
    - setFranchise({ ...franchise, admins: [{ email: e.target.value }] })} - className="peer py-3 px-4 ps-11 block w-full bg-gray-100 border-transparent rounded-lg text-sm focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none" - placeholder="franchisee admin email" - /> -
    - -
    -
    -
    + return ( + +
    + +
    Want to create franchise?
    +
    +
    + + setFranchise({ ...franchise, name: e.target.value }) + } + className="peer py-3 px-4 ps-11 block w-full bg-gray-100 border-transparent rounded-lg text-sm focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none" + placeholder="franchise name" + /> +
    + +
    +
    +
    + + setFranchise({ + ...franchise, + admins: [{ email: e.target.value }], + }) + } + className="peer py-3 px-4 ps-11 block w-full bg-gray-100 border-transparent rounded-lg text-sm focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none" + placeholder="franchisee admin email" + /> +
    + +
    +
    +
    -
    -
    - ); +
    +
    + ); } diff --git a/src/views/createStore.tsx b/src/views/createStore.tsx index 924f98ed2..1846d653f 100644 --- a/src/views/createStore.tsx +++ b/src/views/createStore.tsx @@ -9,41 +9,45 @@ import { pizzaService } from '../service/service'; import { Store } from '../service/pizzaService'; export default function CreateStore() { - const state = useLocation().state; - const navigateToParentPath = useBreadcrumb(); - const [store, setStore] = React.useState({ id: '', name: '' }); + const state = useLocation().state; + const navigateToParentPath = useBreadcrumb(); + const [store, setStore] = React.useState({ id: '', name: '' }); - async function createStore(event: React.FormEvent) { - event.preventDefault(); - await pizzaService.createStore(state.franchise, store); - navigateToParentPath(); - } + async function createStore(event: React.FormEvent) { + event.preventDefault(); + await pizzaService.createStore(state.franchise, store); + navigateToParentPath(); + } - return ( - -
    -
    -
    -
    -
    - setStore({ ...store, name: e.target.value })} - className="peer py-3 px-4 ps-11 block w-full bg-gray-100 border-transparent rounded-lg text-sm focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none" - placeholder="store name" - /> -
    - -
    -
    -
    -
    + return ( + +
    + +
    +
    +
    + setStore({ ...store, name: e.target.value })} + className="peer py-3 px-4 ps-11 block w-full bg-gray-100 border-transparent rounded-lg text-sm focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none" + placeholder="store name" + /> +
    + +
    +
    +
    +
    -
    -
    - ); +
    +
    + ); } diff --git a/src/views/delivery.tsx b/src/views/delivery.tsx index 703c1916c..342d60b29 100644 --- a/src/views/delivery.tsx +++ b/src/views/delivery.tsx @@ -8,84 +8,127 @@ import { HSOverlay } from 'preline'; import { JWTPayload, Order } from '../service/pizzaService'; export default function Delivery() { - const navigate = useNavigate(); - const location = useLocation(); - const order: Order = location.state?.order || { pizzas: [] }; - const jwt: string = location.state?.jwt || 'error'; - const [jwtPayload, setJwtPayload] = React.useState({ message: 'invalid', payload: "{ error: 'invalid JWT' }" }); + const navigate = useNavigate(); + const location = useLocation(); + const order: Order = location.state?.order || { pizzas: [] }; + const jwt: string = location.state?.jwt || 'error'; + const [jwtPayload, setJwtPayload] = React.useState({ + message: 'invalid', + payload: "{ error: 'invalid JWT' }", + }); - async function verify() { - try { - const r = await pizzaService.verifyOrder(jwt); - setJwtPayload(r); - } catch (e: any) { - setJwtPayload({ ...e, payload: { error: 'invalid JWT. Looks like you have a bad pizza!' } }); + async function verify() { + try { + const r = await pizzaService.verifyOrder(jwt); + setJwtPayload(r); + } catch (e: any) { + setJwtPayload({ + ...e, + payload: { error: 'invalid JWT. Looks like you have a bad pizza!' }, + }); + } + HSOverlay.open(document.getElementById('hs-jwt-modal')!); } - HSOverlay.open(document.getElementById('hs-jwt-modal')!); - } - return ( - -
    - - - - + return ( + +
    + + + + -
    -
    +
    +
    -
    -
    order ID:
    {order.id}
    -
    pie count:
    {order.items?.length}
    -
    total:
    {' '} -
    {order.items?.reduce((a: number, c: any) => a + c.price, 0).toLocaleString()} ₿
    -
    +
    +
    order ID:
    {' '} +
    {order.id}
    +
    pie count:
    {' '} +
    {order.items?.length}
    +
    total:
    {' '} +
    + {order.items + ?.reduce((a: number, c: any) => a + c.price, 0) + .toLocaleString()}{' '} + ₿ +
    +
    -
    - {jwt} -
    -
    - -
    -
    -
    -
    -

    - JWT Pizza - {jwtPayload.message} -

    - -
    -
    -
    {JSON.stringify(jwtPayload.payload, null, 2)}
    +
    + {jwt} +
    -
    - + +
    +
    +
    +
    +

    + JWT Pizza -{' '} + + {jwtPayload.message} + +

    + +
    +
    +
    +                                {JSON.stringify(jwtPayload.payload, null, 2)}
    +                            
    +
    +
    + +
    +
    +
    -
    -
    -
    - - ); + + ); } diff --git a/src/views/dinerDashboard.tsx b/src/views/dinerDashboard.tsx index ae535c386..bca6d70bd 100644 --- a/src/views/dinerDashboard.tsx +++ b/src/views/dinerDashboard.tsx @@ -5,100 +5,132 @@ import { pizzaService } from '../service/service'; import { Order, OrderHistory, Role, User } from '../service/pizzaService'; interface Props { - user: User | null; + user: User | null; } export default function DinerDashboard(props: Props) { - const user = props.user || ({} as User); - const [orders, setOrders] = React.useState([]); + const user = props.user || ({} as User); + const [orders, setOrders] = React.useState([]); - React.useEffect(() => { - (async () => { - if (user) { - const r: OrderHistory = await pizzaService.getOrders(user); - setOrders(r.orders); - } - })(); - }, [user]); + React.useEffect(() => { + (async () => { + if (user) { + const r: OrderHistory = await pizzaService.getOrders(user); + setOrders(r.orders); + } + })(); + }, [user]); - function formatRole(role: { role: Role; objectId?: string }) { - if (role.role === Role.Franchisee) { - return `Franchisee on ${role.objectId}`; - } - - return role.role; - } + function formatRole(role: { role: Role; objectId?: string }) { + if (role.role === Role.Franchisee) { + return `Franchisee on ${role.objectId}`; + } - return ( - -
    -
    - Employee stock photo -
    + return role.role; + } -
    -
    name:
    {user.name}
    -
    email:
    {user.email}
    -
    role:
    {' '} -
    - {user.roles && - user.roles.map((role, index) => ( - - {index === 0 ? '' : ', '} {formatRole(role)} - - ))} -
    -
    + return ( + +
    +
    + Employee stock photo +
    - {orders?.length === 0 && ( -
    - How have you lived this long without having a pizza?{' '} - - Buy one - {' '} - now! -
    - )} - {orders?.length > 0 && ( - <> -
    Here is your history of all the good times.
    -
    -
    -
    -
    -
    - - - - - - - - - - {orders.map((order, index) => ( - - - - - - ))} - -
    - ID - - Price - - Date -
    {order.id}{order.items.reduce((a, c) => a + c.price, 0).toLocaleString()} ₿{order.date.toLocaleString()}
    +
    +
    name:
    {' '} +
    {user.name}
    +
    email:
    {' '} +
    {user.email}
    +
    role:
    {' '} +
    + {user.roles && + user.roles.map((role, index) => ( + + {index === 0 ? '' : ', '} {formatRole(role)} + + ))}
    -
    -
    + + {orders?.length === 0 && ( +
    + How have you lived this long without having a pizza?{' '} + + Buy one + {' '} + now! +
    + )} + {orders?.length > 0 && ( + <> +
    + Here is your history of all the good times. +
    +
    +
    +
    +
    +
    + + + + + + + + + + {orders.map((order, index) => ( + + + + + + ))} + +
    + ID + + Price + + Date +
    + {order.id} + + {order.items + .reduce( + (a, c) => a + c.price, + 0, + ) + .toLocaleString()}{' '} + ₿ + + {order.date.toLocaleString()} +
    +
    +
    +
    +
    +
    + + )}
    - - )} -
    - - ); + + ); } diff --git a/src/views/docs.tsx b/src/views/docs.tsx index bf6a395b8..f443f1bfc 100644 --- a/src/views/docs.tsx +++ b/src/views/docs.tsx @@ -5,52 +5,56 @@ import { useParams } from 'react-router-dom'; import { Endpoints } from '../service/pizzaService'; const apis = [ - { name: 'service', url: import.meta.env.VITE_PIZZA_SERVICE_URL }, - { name: 'factory', url: import.meta.env.VITE_PIZZA_FACTORY_URL }, + { name: 'service', url: import.meta.env.VITE_PIZZA_SERVICE_URL }, + { name: 'factory', url: import.meta.env.VITE_PIZZA_FACTORY_URL }, ]; const Docs = () => { - const { docType } = useParams(); - const [docs, setDocs] = React.useState({ endpoints: [] }); - React.useEffect(() => { - (async () => { - setDocs(await pizzaService.docs(docType!)); - })(); - }, []); + const { docType } = useParams(); + const [docs, setDocs] = React.useState({ endpoints: [] }); + React.useEffect(() => { + (async () => { + setDocs(await pizzaService.docs(docType!)); + })(); + }, []); - return ( - -
    - {docs.endpoints.map((doc, index) => ( -
    -

    - {doc.requiresAuth && 🔐} [{doc.method}] {doc.path} -

    -

    {doc.description}

    + return ( + +
    + {docs.endpoints.map((doc, index) => ( +
    +

    + {doc.requiresAuth && 🔐} [{doc.method}] {doc.path} +

    +

    {doc.description}

    -
    - -
    {doc.example}
    +
    + +
    + {doc.example} +
    +
    +
    + +
    +                                {JSON.stringify(doc.response, null, 2)}
    +                            
    +
    +
    + ))}
    -
    - -
    {JSON.stringify(doc.response, null, 2)}
    +
    + {apis.map((api, index) => ( +
    + {api.name}:  + + {api.url} + +
    + ))}
    -
    - ))} -
    -
    - {apis.map((api, index) => ( -
    - {api.name}:  - - {api.url} - -
    - ))} -
    -
    - ); + + ); }; export default Docs; diff --git a/src/views/franchiseDashboard.tsx b/src/views/franchiseDashboard.tsx index a62ee46ee..652c3e90c 100644 --- a/src/views/franchiseDashboard.tsx +++ b/src/views/franchiseDashboard.tsx @@ -8,188 +8,255 @@ import { pizzaService } from '../service/service'; import { Franchise, Store, User } from '../service/pizzaService'; interface Props { - user: User | null; + user: User | null; } export default function FranchiseDashboard(props: Props) { - const navigate = useNavigate(); - const [franchise, setFranchise] = React.useState(null); + const navigate = useNavigate(); + const [franchise, setFranchise] = React.useState(null); - React.useEffect(() => { - (async () => { - if (props.user) { - const franchises = await pizzaService.getFranchise(props.user); - if (franchises.length) setFranchise(franchises[0]); - } - })(); - }, [props.user]); + React.useEffect(() => { + (async () => { + if (props.user) { + const franchises = await pizzaService.getFranchise(props.user); + if (franchises.length) setFranchise(franchises[0]); + } + })(); + }, [props.user]); - function createStore() { - navigate('/franchise-dashboard/create-store', { state: { franchise: franchise } }); - } + function createStore() { + navigate('/franchise-dashboard/create-store', { state: { franchise: franchise } }); + } - function closeStore(franchise: Franchise, store: Store) { - navigate('/franchise-dashboard/close-store', { state: { franchise: franchise, store: store } }); - } + function closeStore(franchise: Franchise, store: Store) { + navigate('/franchise-dashboard/close-store', { + state: { franchise: franchise, store: store }, + }); + } - if (!franchise) { - return whyFranchise(); - } + if (!franchise) { + return whyFranchise(); + } - return ( - -
    Everything you need to run an JWT Pizza franchise. Your gateway to success.
    + return ( + +
    + Everything you need to run an JWT Pizza franchise. Your gateway to success. +
    -
    -
    -
    -
    -
    - - - - {['Name', 'Revenue', 'Action'].map((header) => ( - - ))} - - - - {franchise.stores?.map((store, index) => ( - - - - - - ))} - -
    - {header} -
    {store.name}{store.totalRevenue?.toLocaleString()} ₿ - -
    -
    +
    +
    +
    +
    +
    + + + + {['Name', 'Revenue', 'Action'].map((header) => ( + + ))} + + + + {franchise.stores?.map((store, index) => ( + + + + + + ))} + +
    + {header} +
    + {store.name} + + {store.totalRevenue?.toLocaleString()} ₿ + + +
    +
    +
    +
    +
    -
    -
    -
    -
    -

    , + , + , + , + ]} + /> +

    +

    - Pizza is an absolute delight that brings joy to people of all ages. The perfect combination of crispy crust, savory sauce, and gooey cheese - makes pizza an irresistible treat. At JWT Pizza, we take pride in serving the web's best pizza, crafted with love and passion. Our skilled - chefs use only the finest ingredients to create mouthwatering pizzas that will leave you craving for more. Whether you prefer classic flavors - or adventurous toppings, our diverse menu has something for everyone. So why wait? Indulge in the pizza experience of a lifetime and visit JWT - Pizza today! -

    - -

    - Pizza has come a long way since its humble beginnings. From its origins in Italy to becoming a global sensation, pizza has captured the hearts - and taste buds of people worldwide. It has become a symbol of comfort, celebration, and togetherness. At JWT Pizza, we understand the magic of - pizza and strive to deliver an unforgettable dining experience. Our cozy ambiance, friendly staff, and delectable pizzas create the perfect - setting for a memorable meal. Whether you're dining with family, friends, or enjoying a solo pizza night, Pizza Shop is the place to be. -

    -

    - Pizza is not just a food; it's an experience. The aroma of freshly baked pizza, the sight of melted cheese stretching with every bite, and the - explosion of flavors in your mouth - it's a sensory journey like no other. At JWT Pizza, we believe in the power of pizza to bring people - together. Our inviting atmosphere and warm hospitality make every visit a special occasion. Whether you're celebrating a birthday, - anniversary, or simply craving a delicious meal, JWT Pizza is here to make your experience extraordinary. Join us and discover the magic of - pizza at its finest. -

    -

    - Pizza is a universal language that transcends borders and cultures. It's a dish that brings people from all walks of life together, united by - their love for this culinary masterpiece. At JWT Pizza, we embrace diversity and celebrate the joy of sharing a pizza with friends and family. - Our menu features a wide range of flavors inspired by different cuisines, ensuring there's something for everyone. Whether you're a meat - lover, a vegetarian, or have dietary restrictions, our pizzas are crafted to satisfy every palate. Come and experience the magic of pizza at - JWT Pizza today! -

    - - ); + first-letter:mr-3 first-letter:float-left" + > + Pizza is an absolute delight that brings joy to people of all ages. The perfect + combination of crispy crust, savory sauce, and gooey cheese makes pizza an + irresistible treat. At JWT Pizza, we take pride in serving the web's best pizza, + crafted with love and passion. Our skilled chefs use only the finest ingredients to + create mouthwatering pizzas that will leave you craving for more. Whether you prefer + classic flavors or adventurous toppings, our diverse menu has something for + everyone. So why wait? Indulge in the pizza experience of a lifetime and visit JWT + Pizza today! +

    + +

    + Pizza has come a long way since its humble beginnings. From its origins in Italy to + becoming a global sensation, pizza has captured the hearts and taste buds of people + worldwide. It has become a symbol of comfort, celebration, and togetherness. At JWT + Pizza, we understand the magic of pizza and strive to deliver an unforgettable + dining experience. Our cozy ambiance, friendly staff, and delectable pizzas create + the perfect setting for a memorable meal. Whether you're dining with family, + friends, or enjoying a solo pizza night, Pizza Shop is the place to be. +

    +

    + Pizza is not just a food; it's an experience. The aroma of freshly baked pizza, the + sight of melted cheese stretching with every bite, and the explosion of flavors in + your mouth - it's a sensory journey like no other. At JWT Pizza, we believe in the + power of pizza to bring people together. Our inviting atmosphere and warm + hospitality make every visit a special occasion. Whether you're celebrating a + birthday, anniversary, or simply craving a delicious meal, JWT Pizza is here to make + your experience extraordinary. Join us and discover the magic of pizza at its + finest. +

    +

    + Pizza is a universal language that transcends borders and cultures. It's a dish that + brings people from all walks of life together, united by their love for this + culinary masterpiece. At JWT Pizza, we embrace diversity and celebrate the joy of + sharing a pizza with friends and family. Our menu features a wide range of flavors + inspired by different cuisines, ensuring there's something for everyone. Whether + you're a meat lover, a vegetarian, or have dietary restrictions, our pizzas are + crafted to satisfy every palate. Come and experience the magic of pizza at JWT Pizza + today! +

    + + ); } diff --git a/src/views/login.tsx b/src/views/login.tsx index 77075f8ba..561227efa 100644 --- a/src/views/login.tsx +++ b/src/views/login.tsx @@ -7,102 +7,109 @@ import View from './view'; import { User } from '../service/pizzaService'; interface Props { - setUser: (user: User) => void; + setUser: (user: User) => void; } export default function Login(props: Props) { - const [password, setPassword] = React.useState(''); - const [email, setEmail] = React.useState(''); - const [message, setMessage] = React.useState(''); + const [password, setPassword] = React.useState(''); + const [email, setEmail] = React.useState(''); + const [message, setMessage] = React.useState(''); - const navigateToParent = useBreadcrumb(); - const navigateToRegistration = useBreadcrumb('register'); - const emailRef = React.useRef(null); + const navigateToParent = useBreadcrumb(); + const navigateToRegistration = useBreadcrumb('register'); + const emailRef = React.useRef(null); - useEffect(() => { - emailRef.current?.focus(); - }, []); + useEffect(() => { + emailRef.current?.focus(); + }, []); - async function login(event: React.FormEvent) { - event.preventDefault(); - try { - props.setUser(await pizzaService.login(email, password)); - navigateToParent(); - } catch (error) { - displayMessage(JSON.stringify(error)); + async function login(event: React.FormEvent) { + event.preventDefault(); + try { + props.setUser(await pizzaService.login(email, password)); + navigateToParent(); + } catch (error) { + displayMessage(JSON.stringify(error)); + } } - } - function displayMessage(msg: string) { - setMessage(msg); - } + function displayMessage(msg: string) { + setMessage(msg); + } - return ( - -
    -
    {message}
    + return ( + +
    +
    {message}
    -
    -
    -
    - -
    - setEmail(e.target.value)} - id="email" - className="py-3 ps-11 pe-4 block w-full bg-white/10 border-white/20 text-white placeholder:text-white rounded-lg text-sm focus:border-white/30 focus:ring-white/30 sm:p-4 sm:ps-11" - placeholder="Email address" - /> -
    - -
    -
    -
    -
    - -
    - setPassword(e.target.value)} - className="py-3 ps-11 pe-4 block w-full bg-white/10 border-white/20 text-white placeholder:text-white rounded-lg text-sm focus:border-white/30 focus:ring-white/30 sm:p-4 sm:ps-11" - placeholder="Password" - /> - + +
    +
    + +
    + setEmail(e.target.value)} + id="email" + className="py-3 ps-11 pe-4 block w-full bg-white/10 border-white/20 text-white placeholder:text-white rounded-lg text-sm focus:border-white/30 focus:ring-white/30 sm:p-4 sm:ps-11" + placeholder="Email address" + /> +
    + +
    +
    +
    +
    + +
    + setPassword(e.target.value)} + className="py-3 ps-11 pe-4 block w-full bg-white/10 border-white/20 text-white placeholder:text-white rounded-lg text-sm focus:border-white/30 focus:ring-white/30 sm:p-4 sm:ps-11" + placeholder="Password" + /> + -
    - -
    -
    -
    +
    + +
    +
    +
    -
    -
    -
    - Are you new?{' '} - - Register - {' '} - instead. +
    +
    +
    + Are you new?{' '} + + Register + {' '} + instead. +
    +
    +
    -
    - -
    -
    - ); + + ); } diff --git a/src/views/logout.tsx b/src/views/logout.tsx index e2429c306..ecdbcc025 100644 --- a/src/views/logout.tsx +++ b/src/views/logout.tsx @@ -5,21 +5,21 @@ import View from './view'; import { User } from '../service/pizzaService'; interface Props { - setUser: (user: User | null) => void; + setUser: (user: User | null) => void; } export default function Logout(props: Props) { - const navigate = useNavigate(); + const navigate = useNavigate(); - React.useEffect(() => { - pizzaService.logout(); - props.setUser(null); - navigate('/'); - }, []); + React.useEffect(() => { + pizzaService.logout(); + props.setUser(null); + navigate('/'); + }, []); - return ( - -
    Logging out ...
    -
    - ); + return ( + +
    Logging out ...
    +
    + ); } diff --git a/src/views/menu.tsx b/src/views/menu.tsx index 2389bdefe..68347d370 100644 --- a/src/views/menu.tsx +++ b/src/views/menu.tsx @@ -7,76 +7,107 @@ import { useNavigate, useLocation } from 'react-router-dom'; import { Franchise, Menu, Pizza, Store } from '../service/pizzaService'; export default function Menu() { - const [order, setOrder] = useState(useLocation().state?.order || { items: [] }); - const [menu, setMenu] = useState([]); - const [storeMap, setStoreMap] = useState<{ [key: string]: { store: Store; franchise: Franchise } }>({}); - const [selectedStore, setSelectedStore] = useState(order.storeId || ''); - const navigate = useNavigate(); + const [order, setOrder] = useState(useLocation().state?.order || { items: [] }); + const [menu, setMenu] = useState([]); + const [storeMap, setStoreMap] = useState<{ + [key: string]: { store: Store; franchise: Franchise }; + }>({}); + const [selectedStore, setSelectedStore] = useState(order.storeId || ''); + const navigate = useNavigate(); - useEffect(() => { - (async () => { - const menu = await pizzaService.getMenu(); - setMenu(menu); - const franchiseList = await pizzaService.getFranchises(0, 20, '*'); - const newStoreMap: { [key: string]: { store: Store; franchise: Franchise } } = {}; - franchiseList.franchises.forEach((franchise) => franchise.stores.forEach((store) => (newStoreMap[store.id] = { store, franchise }))); - setStoreMap(newStoreMap); - })(); - }, []); + useEffect(() => { + (async () => { + const menu = await pizzaService.getMenu(); + setMenu(menu); + const franchiseList = await pizzaService.getFranchises(0, 20, '*'); + const newStoreMap: { [key: string]: { store: Store; franchise: Franchise } } = {}; + franchiseList.franchises.forEach((franchise) => + franchise.stores.forEach((store) => (newStoreMap[store.id] = { store, franchise })), + ); + setStoreMap(newStoreMap); + })(); + }, []); - function selectPizza(pizza: Pizza) { - setOrder({ items: [...order.items, { menuId: pizza.id, description: pizza.title, price: pizza.price }] }); - } + function selectPizza(pizza: Pizza) { + setOrder({ + items: [ + ...order.items, + { menuId: pizza.id, description: pizza.title, price: pizza.price }, + ], + }); + } - function checkout(event: React.FormEvent) { - event.preventDefault(); - if (selectedStore && order.items.length > 0) { - order.storeId = selectedStore; - order.franchiseId = storeMap[selectedStore].franchise.id; - navigate('/payment', { state: { order: order } }); + function checkout(event: React.FormEvent) { + event.preventDefault(); + if (selectedStore && order.items.length > 0) { + order.storeId = selectedStore; + order.franchiseId = storeMap[selectedStore].franchise.id; + navigate('/payment', { state: { order: order } }); + } } - } - return ( - -
    -
    -
    Pick your store and pizzas from below. Remember to order extra for a midnight party.
    + return ( + + +
    +
    + Pick your store and pizzas from below. Remember to order extra for a + midnight party. +
    -
    - -
    +
    + +
    -
    {order.items.length > 0 ? 'Selected pizzas: ' + order.items.length : 'What are you waiting for? Pick a store and then add some pizzas!'}
    - - ))} -
    -
    -
    -
    - ); +
    + {menu.map((pizza) => ( + + ))} +
    +
    + +
    + ); } diff --git a/src/views/notFound.tsx b/src/views/notFound.tsx index 4a2ab905f..ec1cd57c7 100644 --- a/src/views/notFound.tsx +++ b/src/views/notFound.tsx @@ -2,9 +2,11 @@ import React from 'react'; import View from './view'; export default function NotFound() { - return ( - -
    It looks like we have dropped a pizza on the floor. Please try another page.
    -
    - ); + return ( + +
    + It looks like we have dropped a pizza on the floor. Please try another page. +
    +
    + ); } diff --git a/src/views/payment.tsx b/src/views/payment.tsx index 072083b4f..0f67411ba 100644 --- a/src/views/payment.tsx +++ b/src/views/payment.tsx @@ -6,87 +6,115 @@ import { pizzaService } from '../service/service'; import { Order, OrderItem } from '../service/pizzaService'; export default function Payment() { - const [errMessage, setErrorMessage] = React.useState(''); - const location = useLocation(); - const order: Order = location.state?.order || { items: [] }; - const navigate = useNavigate(); + const [errMessage, setErrorMessage] = React.useState(''); + const location = useLocation(); + const order: Order = location.state?.order || { items: [] }; + const navigate = useNavigate(); - React.useEffect(() => { - (async () => { - const user = await pizzaService.getUser(); - if (!user) { - const loginPath = location.pathname + '/login'; - navigate(loginPath, { state: location.state }); - } - })(); - }, []); + React.useEffect(() => { + (async () => { + const user = await pizzaService.getUser(); + if (!user) { + const loginPath = location.pathname + '/login'; + navigate(loginPath, { state: location.state }); + } + })(); + }, []); - async function processPayment() { - try { - const confirmation = await pizzaService.order(order); - navigate('/delivery', { state: { order: confirmation.order, jwt: confirmation.jwt } }); - } catch (err: any) { - setErrorMessage(err.message); + async function processPayment() { + try { + const confirmation = await pizzaService.order(order); + navigate('/delivery', { state: { order: confirmation.order, jwt: confirmation.jwt } }); + } catch (err: any) { + setErrorMessage(err.message); + } } - } - function cancel() { - navigate('/menu', { state: { order: order } }); - } + function cancel() { + navigate('/menu', { state: { order: order } }); + } - return ( - -
    - {errMessage &&
    ⚠️ {errMessage}
    } - {!errMessage && order.items.length === 1 &&
    Send me that pizza right now!
    } - {!errMessage && order.items.length > 1 && ( -
    Send me those {order.items.length} pizzas right now!
    - )} -
    -
    -
    -
    -
    -
    -
    - - - - - - - - - {order.items.map((item: OrderItem, index: number) => ( - - - - - ))} - - - - - - - -
    - Pie - - Price -
    {item.description}{item.price.toLocaleString()} ₿
    - {order.items.length} pie{order.items.length > 1 ? 's' : ''} - - {order.items.reduce((a: any, c: any) => a + c.price, 0).toLocaleString()} ₿ -
    + return ( + +
    + {errMessage && ( +
    + ⚠️ {errMessage} +
    + )} + {!errMessage && order.items.length === 1 && ( +
    + Send me that pizza right now! +
    + )} + {!errMessage && order.items.length > 1 && ( +
    + Send me those {order.items.length} pizzas right now! +
    + )} +
    +
    +
    +
    +
    +
    +
    + + + + + + + + + {order.items.map((item: OrderItem, index: number) => ( + + + + + ))} + + + + + + + +
    + Pie + + Price +
    + {item.description} + + {item.price.toLocaleString()} ₿ +
    + {order.items.length} pie + {order.items.length > 1 ? 's' : ''} + + {order.items + .reduce((a: any, c: any) => a + c.price, 0) + .toLocaleString()}{' '} + ₿ +
    +
    +
    +
    +
    -
    -
    -
    -
    - - ); + + ); } diff --git a/src/views/register.tsx b/src/views/register.tsx index 3d7cd63d0..b0775dd7d 100644 --- a/src/views/register.tsx +++ b/src/views/register.tsx @@ -7,118 +7,125 @@ import View from './view'; import { User } from '../service/pizzaService'; interface Props { - setUser: (user: User) => void; + setUser: (user: User) => void; } export default function Register(props: Props) { - const [name, setName] = React.useState(''); - const [password, setPassword] = React.useState(''); - const [email, setEmail] = React.useState(''); - const [message, setMessage] = React.useState(''); + const [name, setName] = React.useState(''); + const [password, setPassword] = React.useState(''); + const [email, setEmail] = React.useState(''); + const [message, setMessage] = React.useState(''); - const navigateToParentPath = useBreadcrumb(); - const navigateToLogin = useBreadcrumb('login'); - const nameRef = React.useRef(null); + const navigateToParentPath = useBreadcrumb(); + const navigateToLogin = useBreadcrumb('login'); + const nameRef = React.useRef(null); - useEffect(() => { - nameRef.current?.focus(); - }, []); + useEffect(() => { + nameRef.current?.focus(); + }, []); - async function register(event: React.FormEvent) { - event.preventDefault(); - try { - props.setUser(await pizzaService.register(name, email, password)); - navigateToParentPath(); - } catch (error) { - displayMessage(JSON.stringify(error)); + async function register(event: React.FormEvent) { + event.preventDefault(); + try { + props.setUser(await pizzaService.register(name, email, password)); + navigateToParentPath(); + } catch (error) { + displayMessage(JSON.stringify(error)); + } } - } - function displayMessage(msg: string) { - setMessage(msg); - } + function displayMessage(msg: string) { + setMessage(msg); + } - return ( - -
    -
    {message}
    + return ( + +
    +
    {message}
    -
    -
    -
    - -
    - setName(e.target.value)} - id="name" - className="py-3 ps-11 pe-4 block w-full bg-white/10 border-white/20 text-white placeholder:text-white rounded-lg text-sm focus:border-white/30 focus:ring-white/30 sm:p-4 sm:ps-11" - placeholder="Full name" - /> -
    - -
    -
    -
    -
    - setEmail(e.target.value)} - id="email" - className="py-3 ps-11 pe-4 block w-full bg-white/10 border-white/20 text-white placeholder:text-white rounded-lg text-sm focus:border-white/30 focus:ring-white/30 sm:p-4 sm:ps-11" - placeholder="Email address" - /> -
    - -
    -
    -
    - -
    - setPassword(e.target.value)} - className="py-3 ps-11 pe-4 block w-full bg-white/10 border-white/20 text-white placeholder:text-white rounded-lg text-sm focus:border-white/30 focus:ring-white/30 sm:p-4 sm:ps-11" - placeholder="Password" - /> - + +
    +
    + +
    + setName(e.target.value)} + id="name" + className="py-3 ps-11 pe-4 block w-full bg-white/10 border-white/20 text-white placeholder:text-white rounded-lg text-sm focus:border-white/30 focus:ring-white/30 sm:p-4 sm:ps-11" + placeholder="Full name" + /> +
    + +
    +
    +
    +
    + setEmail(e.target.value)} + id="email" + className="py-3 ps-11 pe-4 block w-full bg-white/10 border-white/20 text-white placeholder:text-white rounded-lg text-sm focus:border-white/30 focus:ring-white/30 sm:p-4 sm:ps-11" + placeholder="Email address" + /> +
    + +
    +
    +
    + +
    + setPassword(e.target.value)} + className="py-3 ps-11 pe-4 block w-full bg-white/10 border-white/20 text-white placeholder:text-white rounded-lg text-sm focus:border-white/30 focus:ring-white/30 sm:p-4 sm:ps-11" + placeholder="Password" + /> + -
    - -
    -
    -
    +
    + +
    +
    +
    -
    -
    -
    - Already have an account?{' '} - - Login - {' '} - instead. +
    +
    +
    + Already have an account?{' '} + + Login + {' '} + instead. +
    +
    +
    -
    - -
    -
    - ); + + ); } diff --git a/src/views/view.tsx b/src/views/view.tsx index 2f1abeb8b..ef884cc1b 100644 --- a/src/views/view.tsx +++ b/src/views/view.tsx @@ -1,24 +1,26 @@ import React from 'react'; interface Props { - title: string; - children: React.ReactNode; + title: string; + children: React.ReactNode; } export default function View(props: Props) { - return ( - <> -
    -
    -
    -

    - {props.title} -

    -
    + return ( + <> +
    +
    +
    +

    + + {props.title} + +

    +
    - {props.children} -
    -
    - - ); + {props.children} +
    +
    + + ); } From 2c6a44cd9f046426db6fadde55a2b67d816838a7 Mon Sep 17 00:00:00 2001 From: Cooper Motyer <146262493+cjmot@users.noreply.github.com> Date: Tue, 10 Feb 2026 12:24:51 -0700 Subject: [PATCH 26/42] Update README.md From 5d43e0c4c87a4e700c09d73d8e60c1aede958f4f Mon Sep 17 00:00:00 2001 From: Cooper Motyer <146262493+cjmot@users.noreply.github.com> Date: Tue, 10 Feb 2026 12:35:00 -0700 Subject: [PATCH 27/42] Update README.md (again) From 403ad7785dabf1032f66e4053e54198c076431c6 Mon Sep 17 00:00:00 2001 From: Cooper Motyer <146262493+cjmot@users.noreply.github.com> Date: Tue, 10 Feb 2026 12:47:31 -0700 Subject: [PATCH 28/42] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 48865847a..90bff1aa9 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # 🍕 JWT Pizza -![Coverage badge](https://pizza-factory.cs329.click/api/badge/cjmotyer/jwtpizzacoverage)
    +![Coverage badge](https://pizza-factory.cs329.click/api/badge/cjmotyer/jwtpizzacoverage) [![CI Pipeline](https://github.com/cjmot/jwt-pizza/actions/workflows/ci.yml/badge.svg)](https://github.com/cjmot/jwt-pizza/actions/workflows/ci.yml) A JSON Web Token, or [JWT](https://jwt.io/introduction), (pronounced JOT) is a digitally signed transfer of information From b6137e43dddbbe5a82c2a53f70782232a2504312 Mon Sep 17 00:00:00 2001 From: cjmot Date: Thu, 19 Feb 2026 16:39:42 -0700 Subject: [PATCH 29/42] update ci to deploy to aws --- .github/workflows/ci.yml | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8010da17c..2b0ecd23a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,6 @@ jobs: - name: Build run: | npm ci && npm run build - cp dist/index.html dist/404.html - name: Run tests run: | @@ -44,20 +43,34 @@ jobs: color=$(echo "$coverage < 80" | bc | awk '{if ($1) print "red"; else print "green"}') curl -s -X POST "https://pizza-factory.cs329.click/api/badge/${{ secrets.NET_ID }}/jwtpizzacoverage?label=Coverage&value=$coverage%25&color=$color" -H "authorization: bearer ${{ secrets.FACTORY_API_KEY }}" - - name: Update pages artifact - uses: actions/upload-pages-artifact@v3 + - name: Update dist artifact + uses: actions/upload-artifact@v4 with: + name: package path: dist/ deploy: needs: build permissions: - pages: write id-token: write - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest + env: + version: ${{needs.build.outputs.version}} steps: - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v4 + - name: Create OIDC token to AWS + uses: aws-actions/configure-aws-credentials@v4 + with: + audience: sts.amazonaws.com + aws-region: us-east-1 + role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT }}:role/${{ secrets.CI_IAM_ROLE }} + + - name: Download dist artifact + uses: actions/download-artifact@v4 + with: + name: package + path: dist/ + + - name: Push to AWS S3 + run: | + echo Deploying $version + aws s3 cp dist s3://${{ secrets.APP_BUCKET }} --recursive + aws cloudfront create-invalidation --distribution-id ${{ secrets.DISTRIBUTION_ID }} --paths "/*" From 39ad4d5ab622ff542dd4cc6dd113ed95c696d2f4 Mon Sep 17 00:00:00 2001 From: cjmot <146262493+cjmot@users.noreply.github.com> Date: Sat, 21 Feb 2026 12:38:18 -0700 Subject: [PATCH 30/42] tdd before first test fail --- package-lock.json | 1518 ++++++++++++++++------------------ src/views/dinerDashboard.tsx | 50 ++ tests/user.spec.ts | 32 + 3 files changed, 777 insertions(+), 823 deletions(-) create mode 100644 tests/user.spec.ts diff --git a/package-lock.json b/package-lock.json index bb1853bac..99d23855e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,6 +35,7 @@ "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -73,7 +74,6 @@ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -99,6 +99,13 @@ "url": "https://opencollective.com/babel" } }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, "node_modules/@babel/core/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -110,9 +117,9 @@ } }, "node_modules/@babel/generator": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz", - "integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==", + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "dev": true, "license": "MIT", "dependencies": { @@ -143,16 +150,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -773,6 +770,91 @@ "node": ">=12" } }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -827,6 +909,7 @@ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.0.0" } @@ -854,6 +937,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -867,6 +951,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } @@ -876,6 +961,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -896,14 +982,14 @@ } }, "node_modules/@playwright/test": { - "version": "1.58.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.58.1.tgz", - "integrity": "sha512-6LdVIUERWxQMmUSSQi0I53GgCBYgM2RpGngCPY7hSeju+VrKjq3lvs7HpJoPbDiY5QM5EYRtRX5fvrinnMAz3w==", + "version": "1.58.2", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.58.2.tgz", + "integrity": "sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA==", "dev": true, "license": "Apache-2.0", "peer": true, "dependencies": { - "playwright": "1.58.1" + "playwright": "1.58.2" }, "bin": { "playwright": "cli.js" @@ -916,23 +1002,25 @@ "version": "2.11.8", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/popperjs" } }, "node_modules/@remix-run/router": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.15.3.tgz", - "integrity": "sha512-Oy8rmScVrVxWZVOpEF57ovlnhpZ8CCPlnIIumVcV9nFdiSIrus99+Lw78ekXyGvVDlIsFJbSfmSovJUhCWYV3w==", + "version": "1.23.2", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.2.tgz", + "integrity": "sha512-Ic6m2U/rMjTkhERIa/0ZtXJP17QUi2CbWE7cqx4J58M8aA3QTfW+2UlQ4psvTX9IO1RfNVhK3pcpdjej7L+t2w==", + "license": "MIT", "engines": { "node": ">=14.0.0" } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz", - "integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==", + "version": "4.58.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.58.0.tgz", + "integrity": "sha512-mr0tmS/4FoVk1cnaeN244A/wjvGDNItZKR8hRhnmCzygyRXYtKF5jVDSIILR1U97CTzAYmbgIj/Dukg62ggG5w==", "cpu": [ "arm" ], @@ -944,9 +1032,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz", - "integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==", + "version": "4.58.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.58.0.tgz", + "integrity": "sha512-+s++dbp+/RTte62mQD9wLSbiMTV+xr/PeRJEc/sFZFSBRlHPNPVaf5FXlzAL77Mr8FtSfQqCN+I598M8U41ccQ==", "cpu": [ "arm64" ], @@ -958,9 +1046,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz", - "integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==", + "version": "4.58.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.58.0.tgz", + "integrity": "sha512-MFWBwTcYs0jZbINQBXHfSrpSQJq3IUOakcKPzfeSznONop14Pxuqa0Kg19GD0rNBMPQI2tFtu3UzapZpH0Uc1Q==", "cpu": [ "arm64" ], @@ -972,9 +1060,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz", - "integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==", + "version": "4.58.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.58.0.tgz", + "integrity": "sha512-yiKJY7pj9c9JwzuKYLFaDZw5gma3fI9bkPEIyofvVfsPqjCWPglSHdpdwXpKGvDeYDms3Qal8qGMEHZ1M/4Udg==", "cpu": [ "x64" ], @@ -986,9 +1074,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz", - "integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==", + "version": "4.58.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.58.0.tgz", + "integrity": "sha512-x97kCoBh5MOevpn/CNK9W1x8BEzO238541BGWBc315uOlN0AD/ifZ1msg+ZQB05Ux+VF6EcYqpiagfLJ8U3LvQ==", "cpu": [ "arm64" ], @@ -1000,9 +1088,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz", - "integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==", + "version": "4.58.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.58.0.tgz", + "integrity": "sha512-Aa8jPoZ6IQAG2eIrcXPpjRcMjROMFxCt1UYPZZtCxRV68WkuSigYtQ/7Zwrcr2IvtNJo7T2JfDXyMLxq5L4Jlg==", "cpu": [ "x64" ], @@ -1014,9 +1102,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz", - "integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==", + "version": "4.58.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.58.0.tgz", + "integrity": "sha512-Ob8YgT5kD/lSIYW2Rcngs5kNB/44Q2RzBSPz9brf2WEtcGR7/f/E9HeHn1wYaAwKBni+bdXEwgHvUd0x12lQSA==", "cpu": [ "arm" ], @@ -1028,9 +1116,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz", - "integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==", + "version": "4.58.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.58.0.tgz", + "integrity": "sha512-K+RI5oP1ceqoadvNt1FecL17Qtw/n9BgRSzxif3rTL2QlIu88ccvY+Y9nnHe/cmT5zbH9+bpiJuG1mGHRVwF4Q==", "cpu": [ "arm" ], @@ -1042,9 +1130,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz", - "integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==", + "version": "4.58.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.58.0.tgz", + "integrity": "sha512-T+17JAsCKUjmbopcKepJjHWHXSjeW7O5PL7lEFaeQmiVyw4kkc5/lyYKzrv6ElWRX/MrEWfPiJWqbTvfIvjM1Q==", "cpu": [ "arm64" ], @@ -1056,9 +1144,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz", - "integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==", + "version": "4.58.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.58.0.tgz", + "integrity": "sha512-cCePktb9+6R9itIJdeCFF9txPU7pQeEHB5AbHu/MKsfH/k70ZtOeq1k4YAtBv9Z7mmKI5/wOLYjQ+B9QdxR6LA==", "cpu": [ "arm64" ], @@ -1070,9 +1158,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz", - "integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==", + "version": "4.58.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.58.0.tgz", + "integrity": "sha512-iekUaLkfliAsDl4/xSdoCJ1gnnIXvoNz85C8U8+ZxknM5pBStfZjeXgB8lXobDQvvPRCN8FPmmuTtH+z95HTmg==", "cpu": [ "loong64" ], @@ -1084,9 +1172,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz", - "integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==", + "version": "4.58.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.58.0.tgz", + "integrity": "sha512-68ofRgJNl/jYJbxFjCKE7IwhbfxOl1muPN4KbIqAIe32lm22KmU7E8OPvyy68HTNkI2iV/c8y2kSPSm2mW/Q9Q==", "cpu": [ "loong64" ], @@ -1098,9 +1186,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz", - "integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==", + "version": "4.58.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.58.0.tgz", + "integrity": "sha512-dpz8vT0i+JqUKuSNPCP5SYyIV2Lh0sNL1+FhM7eLC457d5B9/BC3kDPp5BBftMmTNsBarcPcoz5UGSsnCiw4XQ==", "cpu": [ "ppc64" ], @@ -1112,9 +1200,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz", - "integrity": "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==", + "version": "4.58.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.58.0.tgz", + "integrity": "sha512-4gdkkf9UJ7tafnweBCR/mk4jf3Jfl0cKX9Np80t5i78kjIH0ZdezUv/JDI2VtruE5lunfACqftJ8dIMGN4oHew==", "cpu": [ "ppc64" ], @@ -1126,9 +1214,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz", - "integrity": "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==", + "version": "4.58.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.58.0.tgz", + "integrity": "sha512-YFS4vPnOkDTD/JriUeeZurFYoJhPf9GQQEF/v4lltp3mVcBmnsAdjEWhr2cjUCZzZNzxCG0HZOvJU44UGHSdzw==", "cpu": [ "riscv64" ], @@ -1140,9 +1228,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz", - "integrity": "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==", + "version": "4.58.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.58.0.tgz", + "integrity": "sha512-x2xgZlFne+QVNKV8b4wwaCS8pwq3y14zedZ5DqLzjdRITvreBk//4Knbcvm7+lWmms9V9qFp60MtUd0/t/PXPw==", "cpu": [ "riscv64" ], @@ -1154,9 +1242,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz", - "integrity": "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==", + "version": "4.58.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.58.0.tgz", + "integrity": "sha512-jIhrujyn4UnWF8S+DHSkAkDEO3hLX0cjzxJZPLF80xFyzyUIYgSMRcYQ3+uqEoyDD2beGq7Dj7edi8OnJcS/hg==", "cpu": [ "s390x" ], @@ -1168,9 +1256,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz", - "integrity": "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==", + "version": "4.58.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.58.0.tgz", + "integrity": "sha512-+410Srdoh78MKSJxTQ+hZ/Mx+ajd6RjjPwBPNd0R3J9FtL6ZA0GqiiyNjCO9In0IzZkCNrpGymSfn+kgyPQocg==", "cpu": [ "x64" ], @@ -1182,9 +1270,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz", - "integrity": "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==", + "version": "4.58.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.58.0.tgz", + "integrity": "sha512-ZjMyby5SICi227y1MTR3VYBpFTdZs823Rs/hpakufleBoufoOIB6jtm9FEoxn/cgO7l6PM2rCEl5Kre5vX0QrQ==", "cpu": [ "x64" ], @@ -1196,9 +1284,9 @@ ] }, "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz", - "integrity": "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==", + "version": "4.58.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.58.0.tgz", + "integrity": "sha512-ds4iwfYkSQ0k1nb8LTcyXw//ToHOnNTJtceySpL3fa7tc/AsE+UpUFphW126A6fKBGJD5dhRvg8zw1rvoGFxmw==", "cpu": [ "x64" ], @@ -1210,9 +1298,9 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz", - "integrity": "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==", + "version": "4.58.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.58.0.tgz", + "integrity": "sha512-fd/zpJniln4ICdPkjWFhZYeY/bpnaN9pGa6ko+5WD38I0tTqk9lXMgXZg09MNdhpARngmxiCg0B0XUamNw/5BQ==", "cpu": [ "arm64" ], @@ -1224,9 +1312,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz", - "integrity": "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==", + "version": "4.58.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.58.0.tgz", + "integrity": "sha512-YpG8dUOip7DCz3nr/JUfPbIUo+2d/dy++5bFzgi4ugOGBIox+qMbbqt/JoORwvI/C9Kn2tz6+Bieoqd5+B1CjA==", "cpu": [ "arm64" ], @@ -1238,9 +1326,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz", - "integrity": "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==", + "version": "4.58.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.58.0.tgz", + "integrity": "sha512-b9DI8jpFQVh4hIXFr0/+N/TzLdpBIoPzjt0Rt4xJbW3mzguV3mduR9cNgiuFcuL/TeORejJhCWiAXe3E/6PxWA==", "cpu": [ "ia32" ], @@ -1252,9 +1340,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz", - "integrity": "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==", + "version": "4.58.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.58.0.tgz", + "integrity": "sha512-CSrVpmoRJFN06LL9xhkitkwUcTZtIotYAF5p6XOR2zW0Zz5mzb3IPpcoPhB02frzMHFNo1reQ9xSF5fFm3hUsQ==", "cpu": [ "x64" ], @@ -1266,9 +1354,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz", - "integrity": "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==", + "version": "4.58.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.58.0.tgz", + "integrity": "sha512-QFsBgQNTnh5K0t/sBsjJLq24YVqEIVkGpfN2VHsnN90soZyhaiA9UUHufcctVNL4ypJY0wrwad0wslx2KJQ1/w==", "cpu": [ "x64" ], @@ -1297,45 +1385,49 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "25.2.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.0.tgz", - "integrity": "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w==", + "version": "25.3.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.0.tgz", + "integrity": "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "undici-types": "~7.16.0" + "undici-types": "~7.18.0" } }, "node_modules/@types/prop-types": { - "version": "15.7.12", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", - "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", - "dev": true + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "dev": true, + "license": "MIT" }, "node_modules/@types/react": { - "version": "18.3.3", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", - "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", + "version": "18.3.28", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.28.tgz", + "integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==", "dev": true, + "license": "MIT", + "peer": true, "dependencies": { "@types/prop-types": "*", - "csstype": "^3.0.2" + "csstype": "^3.2.2" } }, "node_modules/@types/react-dom": { - "version": "18.3.0", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", - "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", "dev": true, - "dependencies": { - "@types/react": "*" + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" } }, "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "dev": true, "license": "MIT", "peer": true, @@ -1371,26 +1463,26 @@ } }, "node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "node": ">=8" } }, "node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">=12" + "node": ">=8" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" @@ -1400,13 +1492,15 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, + "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -1439,7 +1533,8 @@ "version": "5.0.2", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/argparse": { "version": "1.0.10", @@ -1452,9 +1547,9 @@ } }, "node_modules/autoprefixer": { - "version": "10.4.19", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz", - "integrity": "sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==", + "version": "10.4.24", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.24.tgz", + "integrity": "sha512-uHZg7N9ULTVbutaIsDRoUkoS8/h3bdsmVJYZ5l3wv8Cp/6UIIoRDm90hZ+BwxUj/hGBEzLxdHNSKuFpn8WOyZw==", "dev": true, "funding": [ { @@ -1470,12 +1565,12 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "browserslist": "^4.23.0", - "caniuse-lite": "^1.0.30001599", - "fraction.js": "^4.3.7", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", + "browserslist": "^4.28.1", + "caniuse-lite": "^1.0.30001766", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, "bin": { @@ -1492,16 +1587,20 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.9.19", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz", - "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", + "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", "dev": true, "license": "Apache-2.0", "bin": { - "baseline-browser-mapping": "dist/cli.js" + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" } }, "node_modules/binary-extensions": { @@ -1509,6 +1608,7 @@ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -1517,21 +1617,24 @@ } }, "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, + "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -1603,14 +1706,15 @@ "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6" } }, "node_modules/caniuse-lite": { - "version": "1.0.30001767", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001767.tgz", - "integrity": "sha512-34+zUAMhSH+r+9eKmYG+k2Rpt8XttfE4yXAjoZvkAPs15xcYQhyBYdalJ65BzivAvGRMViEjy6oKr/S91loekQ==", + "version": "1.0.30001770", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001770.tgz", + "integrity": "sha512-x/2CLQ1jHENRbHg5PSId2sXq1CIO1CISvwWAj027ltMVG2UNgW+w9oH2+HzgEIRFembL8bUlXtfbBHR1fCg2xw==", "dev": true, "funding": [ { @@ -1633,6 +1737,7 @@ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, + "license": "MIT", "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -1657,6 +1762,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -1686,82 +1792,6 @@ "wrap-ansi": "^6.2.0" } }, - "node_modules/cliui/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/cliui/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/cliui/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1787,6 +1817,7 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6" } @@ -1806,9 +1837,9 @@ "license": "MIT" }, "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", "dev": true, "license": "MIT" }, @@ -1832,6 +1863,7 @@ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true, + "license": "MIT", "bin": { "cssesc": "bin/cssesc" }, @@ -1840,10 +1872,11 @@ } }, "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" }, "node_modules/debug": { "version": "4.4.3", @@ -1893,13 +1926,15 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/dlv": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/eastasianwidth": { "version": "0.2.0", @@ -1909,16 +1944,16 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.286", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz", - "integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==", + "version": "1.5.302", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.302.tgz", + "integrity": "sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg==", "dev": true, "license": "ISC" }, "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, "license": "MIT" }, @@ -2027,16 +2062,17 @@ } }, "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "micromatch": "^4.0.8" }, "engines": { "node": ">=8.6.0" @@ -2047,6 +2083,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -2055,19 +2092,21 @@ } }, "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", "dev": true, + "license": "ISC", "dependencies": { "reusify": "^1.0.4" } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -2124,16 +2163,30 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/fraction.js": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", - "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fraction.js": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", "dev": true, + "license": "MIT", "engines": { "node": "*" }, "funding": { - "type": "patreon", + "type": "github", "url": "https://github.com/sponsors/rawify" } }, @@ -2166,11 +2219,12 @@ "license": "ISC" }, "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -2184,6 +2238,7 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -2219,22 +2274,22 @@ } }, "node_modules/glob": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", - "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, "license": "ISC", "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" }, - "bin": { - "glob": "dist/esm/bin.mjs" + "engines": { + "node": "*" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -2245,6 +2300,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.3" }, @@ -2291,6 +2347,7 @@ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -2349,6 +2406,7 @@ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, + "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" }, @@ -2357,12 +2415,16 @@ } }, "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "dev": true, + "license": "MIT", "dependencies": { - "hasown": "^2.0.0" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2373,6 +2435,7 @@ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -2392,6 +2455,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -2404,6 +2468,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -2549,16 +2614,6 @@ "node": ">=10" } }, - "node_modules/istanbul-lib-source-maps/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/istanbul-reports": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", @@ -2590,10 +2645,12 @@ } }, "node_modules/jiti": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", - "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "dev": true, + "license": "MIT", + "peer": true, "bin": { "jiti": "bin/jiti.js" } @@ -2601,7 +2658,8 @@ "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" }, "node_modules/js-yaml": { "version": "3.14.2", @@ -2644,19 +2702,24 @@ } }, "node_modules/lilconfig": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", "dev": true, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" } }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/locate-path": { "version": "5.0.0", @@ -2682,6 +2745,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, @@ -2690,11 +2754,14 @@ } }, "node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, - "license": "ISC" + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } }, "node_modules/make-dir": { "version": "3.1.0", @@ -2727,17 +2794,19 @@ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -2745,26 +2814,24 @@ } }, "node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": "*" } }, "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "engines": { "node": ">=16 || 14 >=14.17" } @@ -2781,6 +2848,7 @@ "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", "dev": true, + "license": "MIT", "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", @@ -2831,15 +2899,7 @@ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", - "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -2886,86 +2946,12 @@ "node": ">=18" } }, - "node_modules/nyc/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/nyc/node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true, - "license": "MIT" - }, - "node_modules/nyc/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/nyc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/nyc/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/nyc/node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "license": "ISC", - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -2975,6 +2961,7 @@ "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6" } @@ -3098,7 +3085,8 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/path-scurry": { "version": "1.11.1", @@ -3117,6 +3105,13 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -3129,6 +3124,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -3141,15 +3137,17 @@ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/pirates": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", - "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6" } @@ -3168,13 +3166,13 @@ } }, "node_modules/playwright": { - "version": "1.58.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.1.tgz", - "integrity": "sha512-+2uTZHxSCcxjvGc5C891LrS1/NlxglGxzrC4seZiVjcYVQfUa87wBL6rTDqzGjuoWNjnBzRqKmF6zRYGMvQUaQ==", + "version": "1.58.2", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.2.tgz", + "integrity": "sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.58.1" + "playwright-core": "1.58.2" }, "bin": { "playwright": "cli.js" @@ -3187,9 +3185,9 @@ } }, "node_modules/playwright-core": { - "version": "1.58.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.1.tgz", - "integrity": "sha512-bcWzOaTxcW+VOOGBCQgnaKToLJ65d6AqfLVKEWvexyS3AS6rbXl+xdpYRMGSRBClPvyj44njOWoxjNdL/H9UNg==", + "version": "1.58.2", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.2.tgz", + "integrity": "sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==", "dev": true, "license": "Apache-2.0", "bin": { @@ -3209,21 +3207,6 @@ "@playwright/test": "^1.14.1" } }, - "node_modules/playwright/node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/postcss": { "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", @@ -3259,6 +3242,7 @@ "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.0.0", "read-cache": "^1.0.0", @@ -3272,28 +3256,35 @@ } }, "node_modules/postcss-js": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", - "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", + "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", "dependencies": { "camelcase-css": "^2.0.1" }, "engines": { "node": "^12 || ^14 || >= 16" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, "peerDependencies": { "postcss": "^8.4.21" } }, "node_modules/postcss-load-config": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", - "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", "dev": true, "funding": [ { @@ -3305,62 +3296,66 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "lilconfig": "^3.0.0", - "yaml": "^2.3.4" + "lilconfig": "^3.1.1" }, "engines": { - "node": ">= 14" + "node": ">= 18" }, "peerDependencies": { + "jiti": ">=1.21.0", "postcss": ">=8.0.9", - "ts-node": ">=9.0.0" + "tsx": "^4.8.1", + "yaml": "^2.4.2" }, "peerDependenciesMeta": { + "jiti": { + "optional": true + }, "postcss": { "optional": true }, - "ts-node": { + "tsx": { + "optional": true + }, + "yaml": { "optional": true } } }, - "node_modules/postcss-load-config/node_modules/lilconfig": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz", - "integrity": "sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==", + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antonk52" - } - }, - "node_modules/postcss-nested": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", - "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.11" - }, - "engines": { - "node": ">=12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "node": ">=12.0" }, "peerDependencies": { "postcss": "^8.2.14" } }, "node_modules/postcss-selector-parser": { - "version": "6.0.16", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz", - "integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", "dev": true, + "license": "MIT", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -3373,12 +3368,14 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/preline": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/preline/-/preline-2.1.0.tgz", - "integrity": "sha512-7pwrGNPVfGYUv1XHW9i49ejowIVHCDTx8JvbM43hapLi1GCjj9NnAZmTKupxaROboB4Nvp2x0ADBVKAhpmZppA==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/preline/-/preline-2.7.0.tgz", + "integrity": "sha512-xMuMVZ7aftBT1/5/3Rb48i/t+LWQfsUjBX7bls4peqS6h5OZTbIgz0N6eMDzuDlOZF3DiSWLehl00oGlAkvovw==", + "license": "Licensed under MIT and Preline UI Fair Use License", "dependencies": { "@popperjs/core": "^2.11.2" } @@ -3430,12 +3427,14 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", "peer": true, "dependencies": { "loose-envify": "^1.1.0" @@ -3445,24 +3444,26 @@ } }, "node_modules/react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", "peer": true, "dependencies": { "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" + "scheduler": "^0.23.2" }, "peerDependencies": { - "react": "^18.2.0" + "react": "^18.3.1" } }, "node_modules/react-router": { - "version": "6.22.3", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.3.tgz", - "integrity": "sha512-dr2eb3Mj5zK2YISHK++foM9w4eBnO23eKnZEDs7c880P6oKbrjz/Svg9+nxqtHQK+oMW4OtjZca0RqPglXxguQ==", + "version": "6.30.3", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.3.tgz", + "integrity": "sha512-XRnlbKMTmktBkjCLE8/XcZFlnHvr2Ltdr1eJX4idL55/9BbORzyZEaIkBFDhFGCEWBBItsVrDxwx3gnisMitdw==", + "license": "MIT", "dependencies": { - "@remix-run/router": "1.15.3" + "@remix-run/router": "1.23.2" }, "engines": { "node": ">=14.0.0" @@ -3472,12 +3473,13 @@ } }, "node_modules/react-router-dom": { - "version": "6.22.3", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.22.3.tgz", - "integrity": "sha512-7ZILI7HjcE+p31oQvwbokjk6OA/bnFxrhJ19n82Ex9Ph8fNAq+Hm/7KchpMGlTgWhUxRHMMCut+vEtNpWpowKw==", + "version": "6.30.3", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.3.tgz", + "integrity": "sha512-pxPcv1AczD4vso7G4Z3TKcvlxK7g7TNt3/FNGMhfqyntocvYKj+GCatfigGDjbLozC4baguJ0ReCigoDJXb0ag==", + "license": "MIT", "dependencies": { - "@remix-run/router": "1.15.3", - "react-router": "6.22.3" + "@remix-run/router": "1.23.2", + "react-router": "6.30.3" }, "engines": { "node": ">=14.0.0" @@ -3492,6 +3494,7 @@ "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", "dev": true, + "license": "MIT", "dependencies": { "pify": "^2.3.0" } @@ -3501,6 +3504,7 @@ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, + "license": "MIT", "dependencies": { "picomatch": "^2.2.1" }, @@ -3539,18 +3543,22 @@ "license": "ISC" }, "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", "dev": true, + "license": "MIT", "dependencies": { - "is-core-module": "^2.13.0", + "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -3566,10 +3574,11 @@ } }, "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "dev": true, + "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -3592,56 +3601,10 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/rimraf/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/rollup": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", - "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", + "version": "4.58.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.58.0.tgz", + "integrity": "sha512-wbT0mBmWbIvvq8NeEYWWvevvxnOyhKChir47S66WCxw1SXqhw7ssIYejnQEVt7XYQpsj2y8F9PM+Cr3SNEa0gw==", "dev": true, "license": "MIT", "dependencies": { @@ -3655,31 +3618,31 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.57.1", - "@rollup/rollup-android-arm64": "4.57.1", - "@rollup/rollup-darwin-arm64": "4.57.1", - "@rollup/rollup-darwin-x64": "4.57.1", - "@rollup/rollup-freebsd-arm64": "4.57.1", - "@rollup/rollup-freebsd-x64": "4.57.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", - "@rollup/rollup-linux-arm-musleabihf": "4.57.1", - "@rollup/rollup-linux-arm64-gnu": "4.57.1", - "@rollup/rollup-linux-arm64-musl": "4.57.1", - "@rollup/rollup-linux-loong64-gnu": "4.57.1", - "@rollup/rollup-linux-loong64-musl": "4.57.1", - "@rollup/rollup-linux-ppc64-gnu": "4.57.1", - "@rollup/rollup-linux-ppc64-musl": "4.57.1", - "@rollup/rollup-linux-riscv64-gnu": "4.57.1", - "@rollup/rollup-linux-riscv64-musl": "4.57.1", - "@rollup/rollup-linux-s390x-gnu": "4.57.1", - "@rollup/rollup-linux-x64-gnu": "4.57.1", - "@rollup/rollup-linux-x64-musl": "4.57.1", - "@rollup/rollup-openbsd-x64": "4.57.1", - "@rollup/rollup-openharmony-arm64": "4.57.1", - "@rollup/rollup-win32-arm64-msvc": "4.57.1", - "@rollup/rollup-win32-ia32-msvc": "4.57.1", - "@rollup/rollup-win32-x64-gnu": "4.57.1", - "@rollup/rollup-win32-x64-msvc": "4.57.1", + "@rollup/rollup-android-arm-eabi": "4.58.0", + "@rollup/rollup-android-arm64": "4.58.0", + "@rollup/rollup-darwin-arm64": "4.58.0", + "@rollup/rollup-darwin-x64": "4.58.0", + "@rollup/rollup-freebsd-arm64": "4.58.0", + "@rollup/rollup-freebsd-x64": "4.58.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.58.0", + "@rollup/rollup-linux-arm-musleabihf": "4.58.0", + "@rollup/rollup-linux-arm64-gnu": "4.58.0", + "@rollup/rollup-linux-arm64-musl": "4.58.0", + "@rollup/rollup-linux-loong64-gnu": "4.58.0", + "@rollup/rollup-linux-loong64-musl": "4.58.0", + "@rollup/rollup-linux-ppc64-gnu": "4.58.0", + "@rollup/rollup-linux-ppc64-musl": "4.58.0", + "@rollup/rollup-linux-riscv64-gnu": "4.58.0", + "@rollup/rollup-linux-riscv64-musl": "4.58.0", + "@rollup/rollup-linux-s390x-gnu": "4.58.0", + "@rollup/rollup-linux-x64-gnu": "4.58.0", + "@rollup/rollup-linux-x64-musl": "4.58.0", + "@rollup/rollup-openbsd-x64": "4.58.0", + "@rollup/rollup-openharmony-arm64": "4.58.0", + "@rollup/rollup-win32-arm64-msvc": "4.58.0", + "@rollup/rollup-win32-ia32-msvc": "4.58.0", + "@rollup/rollup-win32-x64-gnu": "4.58.0", + "@rollup/rollup-win32-x64-msvc": "4.58.0", "fsevents": "~2.3.2" } }, @@ -3702,22 +3665,24 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } }, "node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" } }, "node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, "license": "ISC", "bin": { @@ -3758,25 +3723,20 @@ } }, "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } + "license": "ISC" }, "node_modules/source-map": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", - "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "license": "BSD-3-Clause", "engines": { - "node": ">= 12" + "node": ">=0.10.0" } }, "node_modules/source-map-js": { @@ -3821,13 +3781,6 @@ "node": ">=8.0.0" } }, - "node_modules/spawn-wrap/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "license": "ISC" - }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -3836,21 +3789,18 @@ "license": "BSD-3-Clause" }, "node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, "node_modules/string-width-cjs": { @@ -3869,24 +3819,7 @@ "node": ">=8" } }, - "node_modules/string-width-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/string-width-cjs/node_modules/strip-ansi": { + "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", @@ -3899,22 +3832,6 @@ "node": ">=8" } }, - "node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/strip-ansi-cjs": { "name": "strip-ansi", "version": "6.0.1", @@ -3929,16 +3846,6 @@ "node": ">=8" } }, - "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/strip-bom": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", @@ -3950,17 +3857,18 @@ } }, "node_modules/sucrase": { - "version": "3.35.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", - "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "version": "3.35.1", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", - "glob": "^10.3.10", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", + "tinyglobby": "^0.2.11", "ts-interface-checker": "^0.1.9" }, "bin": { @@ -3989,6 +3897,7 @@ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -3997,33 +3906,34 @@ } }, "node_modules/tailwindcss": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.3.tgz", - "integrity": "sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==", + "version": "3.4.19", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", + "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", "dev": true, + "license": "MIT", "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", - "chokidar": "^3.5.3", + "chokidar": "^3.6.0", "didyoumean": "^1.2.2", "dlv": "^1.1.3", - "fast-glob": "^3.3.0", + "fast-glob": "^3.3.2", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", - "jiti": "^1.21.0", - "lilconfig": "^2.1.0", - "micromatch": "^4.0.5", + "jiti": "^1.21.7", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.4.23", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.1", - "postcss-nested": "^6.0.1", - "postcss-selector-parser": "^6.0.11", - "resolve": "^1.22.2", - "sucrase": "^3.32.0" + "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" }, "bin": { "tailwind": "lib/cli.js", @@ -4034,18 +3944,18 @@ } }, "node_modules/test-exclude": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", - "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", "dev": true, "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", - "glob": "^10.4.1", - "minimatch": "^9.0.4" + "glob": "^7.1.4", + "minimatch": "^3.0.4" }, "engines": { - "node": ">=18" + "node": ">=8" } }, "node_modules/thenify": { @@ -4053,6 +3963,7 @@ "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", "dev": true, + "license": "MIT", "dependencies": { "any-promise": "^1.0.0" } @@ -4062,6 +3973,7 @@ "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", "dev": true, + "license": "MIT", "dependencies": { "thenify": ">= 3.1.0 < 4" }, @@ -4123,6 +4035,7 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -4134,7 +4047,8 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/type-fest": { "version": "0.8.1", @@ -4157,10 +4071,11 @@ } }, "node_modules/typescript": { - "version": "5.5.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", - "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -4170,9 +4085,9 @@ } }, "node_modules/undici-types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", "dev": true, "license": "MIT" }, @@ -4211,7 +4126,8 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/uuid": { "version": "8.3.2", @@ -4318,6 +4234,79 @@ "vite": ">=4 <=7" } }, + "node_modules/vite-plugin-istanbul/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/vite-plugin-istanbul/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/vite-plugin-istanbul/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/vite-plugin-istanbul/node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "node_modules/vite-plugin-istanbul/node_modules/test-exclude": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", + "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^10.4.1", + "minimatch": "^9.0.4" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/vite/node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", @@ -4336,6 +4325,21 @@ } } }, + "node_modules/vite/node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/vite/node_modules/picomatch": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", @@ -4374,21 +4378,18 @@ "license": "ISC" }, "node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "node": ">=8" } }, "node_modules/wrap-ansi-cjs": { @@ -4410,67 +4411,6 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/wrap-ansi-cjs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -4491,13 +4431,6 @@ "typedarray-to-buffer": "^3.1.5" } }, - "node_modules/write-file-atomic/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "license": "ISC" - }, "node_modules/y18n": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", @@ -4512,22 +4445,6 @@ "dev": true, "license": "ISC" }, - "node_modules/yaml": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", - "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", - "dev": true, - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, "node_modules/yargs": { "version": "15.4.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", @@ -4564,51 +4481,6 @@ "engines": { "node": ">=6" } - }, - "node_modules/yargs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/yargs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } } } } diff --git a/src/views/dinerDashboard.tsx b/src/views/dinerDashboard.tsx index bca6d70bd..1ed3bc6e2 100644 --- a/src/views/dinerDashboard.tsx +++ b/src/views/dinerDashboard.tsx @@ -3,6 +3,9 @@ import { Link } from 'react-router-dom'; import View from './view'; import { pizzaService } from '../service/service'; import { Order, OrderHistory, Role, User } from '../service/pizzaService'; +import { CloseIcon } from '../icons'; +import { HSOverlay } from 'preline'; +import Button from '../components/button'; interface Props { user: User | null; @@ -21,6 +24,12 @@ export default function DinerDashboard(props: Props) { })(); }, [user]); + async function updateUser() { + setTimeout(() => { + HSOverlay.close(document.getElementById('hs-jwt-modal')!); + }, 100); + } + function formatRole(role: { role: Role; objectId?: string }) { if (role.role === Role.Franchisee) { return `Franchisee on ${role.objectId}`; @@ -38,6 +47,11 @@ export default function DinerDashboard(props: Props) { src="https://images.unsplash.com/photo-1492562080023-ab3db95bfbce?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=facearea&facepad=2&w=300&h=300&q=80" alt="Employee stock photo" /> +
    @@ -131,6 +145,42 @@ export default function DinerDashboard(props: Props) { )}
    +
    ); } diff --git a/tests/user.spec.ts b/tests/user.spec.ts new file mode 100644 index 000000000..4650d2bb1 --- /dev/null +++ b/tests/user.spec.ts @@ -0,0 +1,32 @@ +import { test, expect } from 'playwright-test-coverage'; + +test('updateUser', async ({ page }) => { + const email = `user${Math.floor(Math.random() * 10000)}@jwt.com`; + await page.goto('/'); + await page.getByRole('link', { name: 'Register' }).click(); + await page.getByRole('textbox', { name: 'Full name' }).fill('pizza diner'); + await page.getByRole('textbox', { name: 'Email address' }).fill(email); + await page.getByRole('textbox', { name: 'Password' }).fill('diner'); + await page.getByRole('button', { name: 'Register' }).click(); + + await page.getByRole('link', { name: 'pd' }).click(); + + await expect(page.getByRole('main')).toContainText('pizza diner'); + + await page.getByRole('button', { name: 'Edit' }).click(); + await expect(page.locator('h3')).toContainText('Edit user'); + await page.getByRole('button', { name: 'Update' }).click(); + + await page.waitForSelector('[role="dialog"].hidden', { state: 'attached' }); + + await expect(page.getByRole('main')).toContainText('pizza diner'); + + await page.getByRole('button', { name: 'Edit' }).click(); + await expect(page.locator('h3')).toContainText('Edit user'); + await page.getByRole('textbox').first().fill('pizza dinerx'); + await page.getByRole('button', { name: 'Update' }).click(); + + await page.waitForSelector('[role="dialog"].hidden', { state: 'attached' }); + + await expect(page.getByRole('main')).toContainText('pizza dinerx'); +}); From 11e6c0a5945a938f9dc0bbb00a06f4782c483586 Mon Sep 17 00:00:00 2001 From: cjmot <146262493+cjmot@users.noreply.github.com> Date: Sat, 21 Feb 2026 14:30:15 -0700 Subject: [PATCH 31/42] update user interface to include editUser form --- package-lock.json | 1 + playwright.config.ts | 2 +- src/app/app.tsx | 2 +- src/service/httpPizzaService.ts | 10 +++++++++ src/service/pizzaService.ts | 1 + src/views/dinerDashboard.tsx | 38 ++++++++++++++++++++++++++++++++- tests/user.spec.ts | 19 ++++++++--------- 7 files changed, 60 insertions(+), 13 deletions(-) diff --git a/package-lock.json b/package-lock.json index 99d23855e..a2acdf7f7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -74,6 +74,7 @@ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", diff --git a/playwright.config.ts b/playwright.config.ts index 9bd2197bc..c4f12f8aa 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -10,7 +10,7 @@ export default defineConfig({ timeout: 5000, use: { baseURL: 'http://localhost:5173', - trace: 'retain-on-failure', + trace: 'on-first-retry', }, /* Configure projects for major browsers */ diff --git a/src/app/app.tsx b/src/app/app.tsx index 83bc3c092..eeb668dd4 100644 --- a/src/app/app.tsx +++ b/src/app/app.tsx @@ -66,7 +66,7 @@ export default function App() { { title: 'Diner', to: '/diner-dashboard', - component: , + component: , display: [], }, { title: 'Order', to: '/menu', component: , display: ['nav'] }, diff --git a/src/service/httpPizzaService.ts b/src/service/httpPizzaService.ts index 040a39790..6ccedd2f4 100644 --- a/src/service/httpPizzaService.ts +++ b/src/service/httpPizzaService.ts @@ -86,6 +86,16 @@ class HttpPizzaService implements PizzaService { return Promise.resolve(result); } + async updateUser(updatedUser: User): Promise { + const { user, token } = await this.callEndpoint( + `/api/user/${updatedUser.id}`, + 'PUT', + updatedUser, + ); + localStorage.setItem('token', token); + return Promise.resolve(user); + } + async getMenu(): Promise { return this.callEndpoint('/api/order/menu'); } diff --git a/src/service/pizzaService.ts b/src/service/pizzaService.ts index 6f38eb87d..933169b5a 100644 --- a/src/service/pizzaService.ts +++ b/src/service/pizzaService.ts @@ -101,6 +101,7 @@ interface PizzaService { register(email: string, password: string, role: string): Promise; logout(): void; getUser(): Promise; + updateUser(user: User): Promise; getMenu(): Promise; getOrders(user: User): Promise; order(order: Order): Promise; diff --git a/src/views/dinerDashboard.tsx b/src/views/dinerDashboard.tsx index 1ed3bc6e2..9093c893a 100644 --- a/src/views/dinerDashboard.tsx +++ b/src/views/dinerDashboard.tsx @@ -9,12 +9,17 @@ import Button from '../components/button'; interface Props { user: User | null; + setUser: (user: User) => void; } export default function DinerDashboard(props: Props) { const user = props.user || ({} as User); const [orders, setOrders] = React.useState([]); + const nameRef = React.useRef(null); + const emailRef = React.useRef(null); + const passwordRef = React.useRef(null); + React.useEffect(() => { (async () => { if (user) { @@ -25,6 +30,16 @@ export default function DinerDashboard(props: Props) { }, [user]); async function updateUser() { + let updatedUser: User = { + id: user.id, + name: nameRef.current?.value, + email: emailRef.current?.value, + password: passwordRef.current?.value || undefined, + roles: user.roles, + }; + + await pizzaService.updateUser(updatedUser); + props.setUser(updatedUser); setTimeout(() => { HSOverlay.close(document.getElementById('hs-jwt-modal')!); }, 100); @@ -166,7 +181,28 @@ export default function DinerDashboard(props: Props) {
    - update fields here +
    name:
    + +
    email:
    + +
    password:
    +
    diff --git a/tests/user.spec.ts b/tests/user.spec.ts index 4650d2bb1..53d122d65 100644 --- a/tests/user.spec.ts +++ b/tests/user.spec.ts @@ -10,23 +10,22 @@ test('updateUser', async ({ page }) => { await page.getByRole('button', { name: 'Register' }).click(); await page.getByRole('link', { name: 'pd' }).click(); - - await expect(page.getByRole('main')).toContainText('pizza diner'); - await page.getByRole('button', { name: 'Edit' }).click(); - await expect(page.locator('h3')).toContainText('Edit user'); + await page.getByRole('textbox').first().fill('pizza dinerx'); await page.getByRole('button', { name: 'Update' }).click(); await page.waitForSelector('[role="dialog"].hidden', { state: 'attached' }); - await expect(page.getByRole('main')).toContainText('pizza diner'); + await expect(page.getByRole('main')).toContainText('pizza dinerx'); - await page.getByRole('button', { name: 'Edit' }).click(); - await expect(page.locator('h3')).toContainText('Edit user'); - await page.getByRole('textbox').first().fill('pizza dinerx'); - await page.getByRole('button', { name: 'Update' }).click(); + await page.getByRole('link', { name: 'Logout' }).click(); + await page.getByRole('link', { name: 'Login' }).click(); - await page.waitForSelector('[role="dialog"].hidden', { state: 'attached' }); + await page.getByRole('textbox', { name: 'Email address' }).fill(email); + await page.getByRole('textbox', { name: 'Password' }).fill('diner'); + await page.getByRole('button', { name: 'Login' }).click(); + + await page.getByRole('link', { name: 'pd' }).click(); await expect(page.getByRole('main')).toContainText('pizza dinerx'); }); From 67e10cb59aaa0efc66bfa43d369aa7e116de03cf Mon Sep 17 00:00:00 2001 From: cjmot <146262493+cjmot@users.noreply.github.com> Date: Sat, 21 Feb 2026 15:51:09 -0700 Subject: [PATCH 32/42] Updated ci pipelines --- .github/workflows/test.yml | 11 ---------- .github/workflows/tests.yml | 40 +++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 11 deletions(-) delete mode 100644 .github/workflows/test.yml create mode 100644 .github/workflows/tests.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index 1cfdb774d..000000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,11 +0,0 @@ -name: basic - -on: - workflow_dispatch: - -jobs: - greeter: - runs-on: ubuntu-latest - steps: - - run: echo hello - - run: echo goodbye diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 000000000..465e99f2a --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,40 @@ +name: CI Pipeline + +on: + push: + branches-ignore: + - main + pull_request: + branches: + - main + workflow_dispatch: +jobs: + build: + name: Build + runs-on: ubuntu-latest + outputs: + version: ${{ steps.set_version.outputs.version }} + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: '22.x' + + - name: set version + id: set_version + run: | + version=$(date +'%Y%m%d.%H%M%S') + echo "version=$version" >> "$GITHUB_OUTPUT" + printf '{"version": "%s" }' "$version" > public/version.json + + - name: Build + run: | + npm ci && npm run build + + - name: Run tests + run: | + npx playwright install --with-deps chromium + npm run test:coverage From 7e8d058c2987ef835f31f9bc5b2190f8daa9104a Mon Sep 17 00:00:00 2001 From: cjmot <146262493+cjmot@users.noreply.github.com> Date: Sat, 21 Feb 2026 16:25:04 -0700 Subject: [PATCH 33/42] renamed test pipline to tests --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 465e99f2a..830fa5f13 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,4 +1,4 @@ -name: CI Pipeline +name: tests on: push: From 858fd6adff612c1eaaed28c67044f9fa5bf3fddb Mon Sep 17 00:00:00 2001 From: cjmot <146262493+cjmot@users.noreply.github.com> Date: Sat, 21 Feb 2026 16:56:01 -0700 Subject: [PATCH 34/42] added more tests for updateUser, added better message handling for invalid email or password --- src/views/login.tsx | 7 ++++- tests/helpers.ts | 49 ++++++++++++++++++++++++++---- tests/user.spec.ts | 72 +++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 116 insertions(+), 12 deletions(-) diff --git a/src/views/login.tsx b/src/views/login.tsx index 561227efa..46feb28fa 100644 --- a/src/views/login.tsx +++ b/src/views/login.tsx @@ -29,7 +29,12 @@ export default function Login(props: Props) { props.setUser(await pizzaService.login(email, password)); navigateToParent(); } catch (error) { - displayMessage(JSON.stringify(error)); + console.log(JSON.stringify(error)); + if (JSON.stringify(error).includes('401')) { + displayMessage('Invalid email or password'); + } else { + displayMessage(JSON.stringify(error)); + } } } diff --git a/tests/helpers.ts b/tests/helpers.ts index 90cdadd4a..a987f14e9 100644 --- a/tests/helpers.ts +++ b/tests/helpers.ts @@ -72,7 +72,8 @@ async function basicInit(page: Page) { await route.fulfill({ status: 401, json: { error: 'Unauthorized' } }); return; } - loggedInUser = validUsers[req.email]; + loggedInUser = { ...validUsers[req.email] }; + delete loggedInUser.password; const loginRes = { user: loggedInUser, token: 'abcdef', @@ -82,10 +83,11 @@ async function basicInit(page: Page) { return; } const newUser = { ...req, id: '15', roles: [{ role: Role.Diner }] }; - validUsers[req.email] = newUser; - delete newUser.password; - loggedInUser = newUser; - await route.fulfill({ json: { user: newUser, token: 'abcdef' } }); + validUsers[req.email] = { ...newUser }; + const userResponse = { ...newUser }; + delete userResponse.password; + loggedInUser = userResponse; + await route.fulfill({ json: { user: userResponse, token: 'abcdef' } }); }); // Return the currently logged in user @@ -94,6 +96,43 @@ async function basicInit(page: Page) { await route.fulfill({ json: loggedInUser }); }); + // Update a user + await page.route(/\/api\/user\/(\d+)$/, async (route) => { + expect(route.request().method()).toBe('PUT'); + const userReq = route.request().postDataJSON(); + const userId = route.request().url().split('/').pop(); + + if (!userId) { + await route.fulfill({ status: 400, json: { error: 'missing user id' } }); + return; + } + + const currentEntry = Object.entries(validUsers).find(([, user]) => user.id === userId); + if (!currentEntry) { + await route.fulfill({ status: 404, json: { error: 'user not found' } }); + return; + } + + const [currentEmail, currentUser] = currentEntry; + const updatedUser: User = { + ...currentUser, + ...userReq, + id: currentUser.id, + roles: userReq.roles || currentUser.roles, + password: userReq.password || currentUser.password, + }; + + if (userReq.email && userReq.email !== currentEmail) { + delete validUsers[currentEmail]; + } + validUsers[updatedUser.email || currentEmail] = updatedUser; + + const userResponse = { ...updatedUser }; + delete userResponse.password; + loggedInUser = userResponse; + await route.fulfill({ json: { user: userResponse, token: 'abcdef' } }); + }); + // A standard menu await page.route('*/**/api/order/menu', async (route) => { const menuRes = [ diff --git a/tests/user.spec.ts b/tests/user.spec.ts index 53d122d65..9d7fb3daa 100644 --- a/tests/user.spec.ts +++ b/tests/user.spec.ts @@ -1,25 +1,40 @@ import { test, expect } from 'playwright-test-coverage'; +import { Page } from '@playwright/test'; +import { basicInit } from './helpers'; -test('updateUser', async ({ page }) => { - const email = `user${Math.floor(Math.random() * 10000)}@jwt.com`; +async function registerDiner(page: Page, email: string, password: string = 'diner') { await page.goto('/'); await page.getByRole('link', { name: 'Register' }).click(); await page.getByRole('textbox', { name: 'Full name' }).fill('pizza diner'); await page.getByRole('textbox', { name: 'Email address' }).fill(email); - await page.getByRole('textbox', { name: 'Password' }).fill('diner'); + await page.getByRole('textbox', { name: 'Password' }).fill(password); await page.getByRole('button', { name: 'Register' }).click(); +} +async function openUserEditModal(page: Page) { await page.getByRole('link', { name: 'pd' }).click(); await page.getByRole('button', { name: 'Edit' }).click(); - await page.getByRole('textbox').first().fill('pizza dinerx'); +} + +async function logoutAndOpenLogin(page: Page) { + await page.getByRole('link', { name: 'Logout' }).click(); + await page.getByRole('link', { name: 'Login' }).click(); +} + +test('updateUser', async ({ page }) => { + await basicInit(page); + const email = `user${Math.floor(Math.random() * 10000)}@jwt.com`; + await registerDiner(page, email); + + await openUserEditModal(page); + await page.locator('#hs-jwt-modal input').first().fill('pizza dinerx'); await page.getByRole('button', { name: 'Update' }).click(); await page.waitForSelector('[role="dialog"].hidden', { state: 'attached' }); await expect(page.getByRole('main')).toContainText('pizza dinerx'); - await page.getByRole('link', { name: 'Logout' }).click(); - await page.getByRole('link', { name: 'Login' }).click(); + await logoutAndOpenLogin(page); await page.getByRole('textbox', { name: 'Email address' }).fill(email); await page.getByRole('textbox', { name: 'Password' }).fill('diner'); @@ -29,3 +44,48 @@ test('updateUser', async ({ page }) => { await expect(page.getByRole('main')).toContainText('pizza dinerx'); }); + +test('updateUser email persists across logout/login', async ({ page }) => { + await basicInit(page); + const email = `user${Math.floor(Math.random() * 10000)}@jwt.com`; + const updatedEmail = `updated${Math.floor(Math.random() * 10000)}@jwt.com`; + await registerDiner(page, email); + + await openUserEditModal(page); + await page.locator('#hs-jwt-modal input').nth(1).fill(updatedEmail); + await page.getByRole('button', { name: 'Update' }).click(); + await page.waitForSelector('[role="dialog"].hidden', { state: 'attached' }); + + await expect(page.getByRole('main')).toContainText(updatedEmail); + + await logoutAndOpenLogin(page); + await page.getByRole('textbox', { name: 'Email address' }).fill(updatedEmail); + await page.getByRole('textbox', { name: 'Password' }).fill('diner'); + await page.getByRole('button', { name: 'Login' }).click(); + await page.getByRole('link', { name: 'pd' }).click(); + + await expect(page.getByRole('main')).toContainText(updatedEmail); +}); + +test('updateUser password invalidates old password', async ({ page }) => { + await basicInit(page); + const email = `user${Math.floor(Math.random() * 10000)}@jwt.com`; + const newPassword = 'newDinerPass'; + await registerDiner(page, email); + + await openUserEditModal(page); + await page.locator('#hs-jwt-modal input').nth(2).fill(newPassword); + await page.getByRole('button', { name: 'Update' }).click(); + await page.waitForSelector('[role="dialog"].hidden', { state: 'attached' }); + + await logoutAndOpenLogin(page); + await page.getByRole('textbox', { name: 'Email address' }).fill(email); + await page.getByRole('textbox', { name: 'Password' }).fill('diner'); + await page.getByRole('button', { name: 'Login' }).click(); + await expect(page.getByText('Invalid email or password')).toBeVisible(); + + await page.getByRole('textbox', { name: 'Password' }).fill(newPassword); + await page.getByRole('button', { name: 'Login' }).click(); + await page.getByRole('link', { name: 'pd' }).click(); + await expect(page.getByRole('main')).toContainText('pizza diner'); +}); From 292a9305ada79d528cc8c19c6b97b7de420e64dc Mon Sep 17 00:00:00 2001 From: cjmot <146262493+cjmot@users.noreply.github.com> Date: Sat, 21 Feb 2026 17:19:38 -0700 Subject: [PATCH 35/42] Add listUsers mock and listUsers service route --- src/service/httpPizzaService.ts | 9 +++++++++ src/service/pizzaService.ts | 7 +++++++ tests/helpers.ts | 24 ++++++++++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/src/service/httpPizzaService.ts b/src/service/httpPizzaService.ts index 6ccedd2f4..be5590f61 100644 --- a/src/service/httpPizzaService.ts +++ b/src/service/httpPizzaService.ts @@ -2,6 +2,7 @@ import { PizzaService, Franchise, FranchiseList, + UserList, Store, OrderHistory, User, @@ -86,6 +87,14 @@ class HttpPizzaService implements PizzaService { return Promise.resolve(result); } + async listUsers( + page: number = 0, + limit: number = 10, + nameFilter: string = '*', + ): Promise { + return this.callEndpoint(`/api/user?page=${page}&limit=${limit}&name=${nameFilter}`); + } + async updateUser(updatedUser: User): Promise { const { user, token } = await this.callEndpoint( `/api/user/${updatedUser.id}`, diff --git a/src/service/pizzaService.ts b/src/service/pizzaService.ts index 933169b5a..01259e8ff 100644 --- a/src/service/pizzaService.ts +++ b/src/service/pizzaService.ts @@ -78,6 +78,11 @@ type FranchiseList = { more: boolean; }; +type UserList = { + users: User[]; + more: boolean; +}; + type Endpoint = { requiresAuth: boolean; method: string; @@ -101,6 +106,7 @@ interface PizzaService { register(email: string, password: string, role: string): Promise; logout(): void; getUser(): Promise; + listUsers(page: number, limit: number, nameFilter: string): Promise; updateUser(user: User): Promise; getMenu(): Promise; getOrders(user: User): Promise; @@ -125,6 +131,7 @@ export { Order, Franchise, FranchiseList, + UserList, Store, OrderItem, Endpoint, diff --git a/tests/helpers.ts b/tests/helpers.ts index a987f14e9..f34d4ec53 100644 --- a/tests/helpers.ts +++ b/tests/helpers.ts @@ -96,6 +96,30 @@ async function basicInit(page: Page) { await route.fulfill({ json: loggedInUser }); }); + // List users + await page.route(/\/api\/user(\?.*)$/, async (route) => { + expect(route.request().method()).toBe('GET'); + const url = new URL(route.request().url()); + const nameFilter = (url.searchParams.get('name') || '*').replaceAll('*', '').toLowerCase(); + + const users = Object.values(validUsers) + .filter((user) => { + if (!nameFilter) { + return true; + } + const userName = (user.name || '').toLowerCase(); + const userEmail = (user.email || '').toLowerCase(); + return userName.includes(nameFilter) || userEmail.includes(nameFilter); + }) + .map((user) => { + const responseUser = { ...user }; + delete responseUser.password; + return responseUser; + }); + + await route.fulfill({ json: { users, more: false } }); + }); + // Update a user await page.route(/\/api\/user\/(\d+)$/, async (route) => { expect(route.request().method()).toBe('PUT'); From f99c7c0cf572876e619d7e604ac277c01a560566 Mon Sep 17 00:00:00 2001 From: cjmot <146262493+cjmot@users.noreply.github.com> Date: Sat, 21 Feb 2026 17:20:08 -0700 Subject: [PATCH 36/42] add listUsers tests and list users admin dashboard functionality --- src/views/adminDashboard.tsx | 277 +++++++++++++++++++++++------------ tests/adminFunctions.spec.ts | 80 ++++++++-- 2 files changed, 248 insertions(+), 109 deletions(-) diff --git a/src/views/adminDashboard.tsx b/src/views/adminDashboard.tsx index 0726904b7..1e7001ef3 100644 --- a/src/views/adminDashboard.tsx +++ b/src/views/adminDashboard.tsx @@ -4,7 +4,14 @@ import { useNavigate } from 'react-router-dom'; import NotFound from './notFound'; import Button from '../components/button'; import { pizzaService } from '../service/service'; -import { Franchise, FranchiseList, Role, Store, User } from '../service/pizzaService'; +import { + Franchise, + FranchiseList, + Role, + Store, + User, + UserList, +} from '../service/pizzaService'; import { TrashIcon } from '../icons'; interface Props { @@ -13,18 +20,25 @@ interface Props { export default function AdminDashboard(props: Props) { const navigate = useNavigate(); + const [activeList, setActiveList] = React.useState<'franchises' | 'users'>('franchises'); + const [nameFilter, setNameFilter] = React.useState('*'); const [franchiseList, setFranchiseList] = React.useState({ franchises: [], more: false, }); - const [franchisePage, setFranchisePage] = React.useState(0); + const [userList, setUserList] = React.useState({ users: [], more: false }); + const [listPage, setListPage] = React.useState(0); const filterFranchiseRef = React.useRef(null); React.useEffect(() => { (async () => { - setFranchiseList(await pizzaService.getFranchises(franchisePage, 3, '*')); + if (activeList === 'franchises') { + setFranchiseList(await pizzaService.getFranchises(listPage, 3, nameFilter)); + return; + } + setUserList(await pizzaService.listUsers(listPage, 10, nameFilter)); })(); - }, [props.user, franchisePage]); + }, [props.user, listPage, activeList, nameFilter]); function createFranchise() { navigate('/admin-dashboard/create-franchise'); @@ -39,13 +53,9 @@ export default function AdminDashboard(props: Props) { } async function filterFranchises() { - setFranchiseList( - await pizzaService.getFranchises( - franchisePage, - 10, - `*${filterFranchiseRef.current?.value}*`, - ), - ); + const value = filterFranchiseRef.current?.value?.trim() || ''; + setNameFilter(value ? `*${value}*` : '*'); + setListPage(0); } let response = ; @@ -53,7 +63,45 @@ export default function AdminDashboard(props: Props) { response = (
    -

    Franchises

    +
    + + +
    +

    + {activeList === 'franchises' ? 'Franchises' : 'Users'} +

    @@ -62,13 +110,16 @@ export default function AdminDashboard(props: Props) { - {[ - 'Franchise', - 'Franchisee', - 'Store', - 'Revenue', - 'Action', - ].map((header) => ( + {(activeList === 'franchises' + ? [ + 'Franchise', + 'Franchisee', + 'Store', + 'Revenue', + 'Action', + ] + : ['User', 'Email'] + ).map((header) => ( - {franchiseList.franchises.map((franchise, findex) => { - return ( - - + {activeList === 'franchises' && + franchiseList.franchises.map((franchise, findex) => { + return ( + + + + + + + + {franchise.stores.map( + (store, sindex) => { + return ( + + + + + + ); + }, + )} + + ); + })} + {activeList === 'users' && ( + + {userList.users.map((user, index) => ( + - - - - {franchise.stores.map((store, sindex) => { - return ( - - - - - - ); - })} - - ); - })} + ))} + + )} ))} @@ -243,7 +250,7 @@ export default function AdminDashboard(props: Props) {
    + {franchise.name} + + {franchise.admins + ?.map((o) => o.name) + .join(', ')} + + +
    + {store.name} + + {store.totalRevenue?.toLocaleString()}{' '} + ₿ + + +
    - {franchise.name} - - {franchise.admins - ?.map((o) => o.name) - .join(', ')} + {user.name || 'Unknown user'} - + + {user.email || 'No email'}
    - {store.name} - - {store.totalRevenue?.toLocaleString()}{' '} - ₿ - - -
    @@ -155,7 +226,11 @@ export default function AdminDashboard(props: Props) { type="text" ref={filterFranchiseRef} name="filterFranchise" - placeholder="Filter franchises" + placeholder={ + activeList === 'franchises' + ? 'Filter franchises' + : 'Filter users' + } className="px-2 py-1 text-sm border border-gray-300 rounded-lg" /> @@ -198,13 +279,15 @@ export default function AdminDashboard(props: Props) { -
    -
    + {activeList === 'franchises' && ( +
    +
    + )} ); } diff --git a/tests/adminFunctions.spec.ts b/tests/adminFunctions.spec.ts index 8811f15df..0206b6950 100644 --- a/tests/adminFunctions.spec.ts +++ b/tests/adminFunctions.spec.ts @@ -1,17 +1,20 @@ import { test, expect } from 'playwright-test-coverage'; +import { Page } from '@playwright/test'; import { basicInit } from './helpers'; -test('create and close franchise', async ({ page }) => { - await basicInit(page); - +async function loginAsAdminAndOpenDashboard(page: Page) { await page.getByRole('link', { name: 'Login' }).click(); await page.getByRole('textbox', { name: 'Email address' }).fill('a@jwt.com'); await page.getByRole('textbox', { name: 'Password' }).fill('admin'); await page.getByRole('button', { name: 'Login' }).click(); - await expect(page.getByRole('link', { name: 'Admin' })).toBeVisible(); - - // Admin page await page.getByRole('link', { name: 'Admin' }).click(); +} + +test('create and close franchise', async ({ page }) => { + await basicInit(page); + + await loginAsAdminAndOpenDashboard(page); + await expect(page.getByText("Mama Ricci's kitchen")).toBeVisible(); await expect(page.getByText('LotaPizza')).toBeVisible(); await expect(page.getByRole('cell', { name: 'Lehi' })).toBeVisible(); @@ -43,12 +46,7 @@ test('create and close franchise', async ({ page }) => { test('create and close store as admin', async ({ page }) => { await basicInit(page); - // Login and go to admin page - await page.getByRole('link', { name: 'Login' }).click(); - await page.getByRole('textbox', { name: 'Email address' }).fill('a@jwt.com'); - await page.getByRole('textbox', { name: 'Password' }).fill('admin'); - await page.getByRole('button', { name: 'Login' }).click(); - await page.getByRole('link', { name: 'Admin' }).click(); + await loginAsAdminAndOpenDashboard(page); // Close Spanish Fork store await page.getByRole('row', { name: 'Lehi 450 ₿ Close' }).getByRole('button').click(); @@ -58,3 +56,61 @@ test('create and close store as admin', async ({ page }) => { await page.getByRole('button', { name: 'Close' }).click(); await expect(page.getByRole('cell', { name: 'Lehi' })).toHaveCount(0); }); + +test('admin can switch between franchises and users lists', async ({ page }) => { + await basicInit(page); + await loginAsAdminAndOpenDashboard(page); + + await expect(page.getByRole('button', { name: 'Franchises' })).toBeVisible(); + await expect(page.getByRole('cell', { name: 'LotaPizza' })).toBeVisible(); + + await page.getByRole('button', { name: 'Users' }).click(); + await expect(page.getByRole('heading', { name: 'Users' })).toBeVisible(); + await expect(page.getByRole('cell', { name: 'Pizza Admin' })).toBeVisible(); + await expect(page.getByRole('cell', { name: 'a@jwt.com' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'Add Franchise' })).toHaveCount(0); + + await page.getByRole('button', { name: 'Franchises' }).click(); + await expect(page.getByRole('cell', { name: 'LotaPizza' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'Add Franchise' })).toBeVisible(); +}); + +test('admin can filter users list by name and email', async ({ page }) => { + await basicInit(page); + await loginAsAdminAndOpenDashboard(page); + + await page.getByRole('button', { name: 'Users' }).click(); + await expect(page.getByRole('cell', { name: 'Pizza Admin' })).toBeVisible(); + await expect(page.getByRole('cell', { name: 'Pizza Diner' })).toBeVisible(); + await expect(page.getByRole('cell', { name: 'Pizza Franchisee' })).toBeVisible(); + + await page.getByPlaceholder('Filter users').fill('franchisee'); + await page.getByRole('button', { name: 'Submit' }).click(); + await expect(page.getByRole('cell', { name: 'Pizza Franchisee' })).toBeVisible(); + await expect(page.getByRole('cell', { name: 'Pizza Admin' })).toHaveCount(0); + + await page.getByPlaceholder('Filter users').fill('a@jwt.com'); + await page.getByRole('button', { name: 'Submit' }).click(); + await expect(page.getByRole('cell', { name: 'a@jwt.com' })).toBeVisible(); + await expect(page.getByRole('cell', { name: 'f@jwt.com' })).toHaveCount(0); +}); + +test('users list has no close actions and list filter resets when switching back', async ({ + page, +}) => { + await basicInit(page); + await loginAsAdminAndOpenDashboard(page); + + await page.getByRole('button', { name: 'Users' }).click(); + await expect(page.getByRole('button', { name: 'Close' })).toHaveCount(0); + await expect(page.getByRole('button', { name: 'Add Franchise' })).toHaveCount(0); + + await page.getByPlaceholder('Filter users').fill('franchisee'); + await page.getByRole('button', { name: 'Submit' }).click(); + await expect(page.getByRole('cell', { name: 'Pizza Franchisee' })).toBeVisible(); + await expect(page.getByRole('cell', { name: 'Pizza Admin' })).toHaveCount(0); + + await page.getByRole('button', { name: 'Franchises' }).click(); + await expect(page.getByPlaceholder('Filter franchises')).toHaveValue(''); + await expect(page.getByRole('cell', { name: 'LotaPizza' })).toBeVisible(); +}); From b52de22bf0ac2b688b2be8dc047050e2cfd7311e Mon Sep 17 00:00:00 2001 From: cjmot <146262493+cjmot@users.noreply.github.com> Date: Sat, 21 Feb 2026 17:23:13 -0700 Subject: [PATCH 37/42] add deleteUser route and type --- src/service/httpPizzaService.ts | 4 ++++ src/service/pizzaService.ts | 1 + 2 files changed, 5 insertions(+) diff --git a/src/service/httpPizzaService.ts b/src/service/httpPizzaService.ts index be5590f61..7004519dd 100644 --- a/src/service/httpPizzaService.ts +++ b/src/service/httpPizzaService.ts @@ -105,6 +105,10 @@ class HttpPizzaService implements PizzaService { return Promise.resolve(user); } + async deleteUser(userId: string): Promise { + return this.callEndpoint(`/api/user/${userId}`, 'DELETE'); + } + async getMenu(): Promise { return this.callEndpoint('/api/order/menu'); } diff --git a/src/service/pizzaService.ts b/src/service/pizzaService.ts index 01259e8ff..92635efc1 100644 --- a/src/service/pizzaService.ts +++ b/src/service/pizzaService.ts @@ -108,6 +108,7 @@ interface PizzaService { getUser(): Promise; listUsers(page: number, limit: number, nameFilter: string): Promise; updateUser(user: User): Promise; + deleteUser(userId: string): Promise; getMenu(): Promise; getOrders(user: User): Promise; order(order: Order): Promise; From ba46ec4d1ce28cd12cbc98a3a73817dda68a6422 Mon Sep 17 00:00:00 2001 From: cjmot <146262493+cjmot@users.noreply.github.com> Date: Sat, 21 Feb 2026 17:37:13 -0700 Subject: [PATCH 38/42] add deleteUser component and route for a user deletion confirmation --- src/views/deleteUser.tsx | 41 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/views/deleteUser.tsx diff --git a/src/views/deleteUser.tsx b/src/views/deleteUser.tsx new file mode 100644 index 000000000..527371036 --- /dev/null +++ b/src/views/deleteUser.tsx @@ -0,0 +1,41 @@ +import React from 'react'; +import { useLocation } from 'react-router-dom'; +import { useBreadcrumb } from '../hooks/appNavigation'; +import { pizzaService } from '../service/service'; +import View from './view'; +import Button from '../components/button'; +import { User } from '../service/pizzaService'; + +export default function DeleteUser() { + const state = useLocation().state as { user?: User } | null; + const navigateToParent = useBreadcrumb(); + const user = state?.user; + + async function remove() { + if (!user?.id) { + navigateToParent(); + return; + } + await pizzaService.deleteUser(user.id); + navigateToParent(); + } + + return ( + +
    +
    + Are you sure you want to delete user{' '} + {user?.name || 'Unknown user'}{' '} + ({user?.email || 'No email'})? This + cannot be restored. +
    +
    +
    + ); +} From d61966cc9ba92034dc89c4bbe01629545963946a Mon Sep 17 00:00:00 2001 From: cjmot <146262493+cjmot@users.noreply.github.com> Date: Sat, 21 Feb 2026 17:37:33 -0700 Subject: [PATCH 39/42] add deleteUser route to app.tsx --- src/app/app.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/app/app.tsx b/src/app/app.tsx index eeb668dd4..1a61442df 100644 --- a/src/app/app.tsx +++ b/src/app/app.tsx @@ -18,6 +18,7 @@ import CreateStore from '../views/createStore'; import CreateFranchise from '../views/createFranchise'; import CloseFranchise from '../views/closeFranchise'; import CloseStore from '../views/closeStore'; +import DeleteUser from '../views/deleteUser'; import Payment from '../views/payment'; import NotFound from '../views/notFound'; import Docs from '../views/docs'; @@ -110,6 +111,12 @@ export default function App() { component: , display: [], }, + { + title: 'Delete user', + to: '/:subPath?/delete-user', + component: , + display: [], + }, { title: 'Payment', to: '/payment', component: , display: [] }, { title: 'Delivery', to: '/delivery', component: , display: [] }, { From 6f7d2245ba5ef65c9f93cecfefd7685b5632dee1 Mon Sep 17 00:00:00 2001 From: cjmot <146262493+cjmot@users.noreply.github.com> Date: Sat, 21 Feb 2026 17:38:04 -0700 Subject: [PATCH 40/42] add deleteUser button and tests for user deletion functionality --- src/views/adminDashboard.tsx | 27 +++++++++++++++--------- tests/adminFunctions.spec.ts | 40 ++++++++++++++++++++++++++++++++++++ tests/helpers.ts | 17 ++++++++++++--- 3 files changed, 71 insertions(+), 13 deletions(-) diff --git a/src/views/adminDashboard.tsx b/src/views/adminDashboard.tsx index 1e7001ef3..70195431e 100644 --- a/src/views/adminDashboard.tsx +++ b/src/views/adminDashboard.tsx @@ -4,14 +4,7 @@ import { useNavigate } from 'react-router-dom'; import NotFound from './notFound'; import Button from '../components/button'; import { pizzaService } from '../service/service'; -import { - Franchise, - FranchiseList, - Role, - Store, - User, - UserList, -} from '../service/pizzaService'; +import { Franchise, FranchiseList, Role, Store, User, UserList } from '../service/pizzaService'; import { TrashIcon } from '../icons'; interface Props { @@ -58,6 +51,10 @@ export default function AdminDashboard(props: Props) { setListPage(0); } + function openDeleteUser(user: User) { + navigate('/admin-dashboard/delete-user', { state: { user } }); + } + let response = ; if (Role.isRole(props.user, Role.Admin)) { response = ( @@ -118,7 +115,7 @@ export default function AdminDashboard(props: Props) { 'Revenue', 'Action', ] - : ['User', 'Email'] + : ['User', 'Email', 'Action'] ).map((header) => (
    {user.email || 'No email'} + + +
    diff --git a/tests/adminFunctions.spec.ts b/tests/adminFunctions.spec.ts index 0206b6950..ef5f62e83 100644 --- a/tests/adminFunctions.spec.ts +++ b/tests/adminFunctions.spec.ts @@ -114,3 +114,43 @@ test('users list has no close actions and list filter resets when switching back await expect(page.getByPlaceholder('Filter franchises')).toHaveValue(''); await expect(page.getByRole('cell', { name: 'LotaPizza' })).toBeVisible(); }); + +test('admin can delete a user from users list', async ({ page }) => { + await basicInit(page); + await loginAsAdminAndOpenDashboard(page); + + await page.getByRole('button', { name: 'Users' }).click(); + await expect(page.getByRole('cell', { name: 'Pizza Diner' })).toBeVisible(); + await expect(page.getByRole('cell', { name: 'd@jwt.com' })).toBeVisible(); + + await page + .getByRole('row', { name: 'Pizza Diner d@jwt.com Delete' }) + .getByRole('button', { name: 'Delete' }) + .click(); + await expect(page.getByText('Are you sure you want to delete user')).toBeVisible(); + await expect(page.getByText('Pizza Diner')).toBeVisible(); + await page.getByRole('button', { name: 'Delete' }).click(); + + await page.getByRole('button', { name: 'Users' }).click(); + await expect(page.getByRole('cell', { name: 'Pizza Diner' })).toHaveCount(0); + await expect(page.getByRole('cell', { name: 'd@jwt.com' })).toHaveCount(0); + await expect(page.getByRole('cell', { name: 'Pizza Admin' })).toBeVisible(); +}); + +test('admin can cancel delete user and keep user in list', async ({ page }) => { + await basicInit(page); + await loginAsAdminAndOpenDashboard(page); + + await page.getByRole('button', { name: 'Users' }).click(); + await page + .getByRole('row', { name: 'Pizza Diner d@jwt.com Delete' }) + .getByRole('button', { name: 'Delete' }) + .click(); + + await expect(page.getByText('Are you sure you want to delete user')).toBeVisible(); + await page.getByRole('button', { name: 'Cancel' }).click(); + + await page.getByRole('button', { name: 'Users' }).click(); + await expect(page.getByRole('cell', { name: 'Pizza Diner' })).toBeVisible(); + await expect(page.getByRole('cell', { name: 'd@jwt.com' })).toBeVisible(); +}); diff --git a/tests/helpers.ts b/tests/helpers.ts index f34d4ec53..bb4fa3af0 100644 --- a/tests/helpers.ts +++ b/tests/helpers.ts @@ -100,7 +100,7 @@ async function basicInit(page: Page) { await page.route(/\/api\/user(\?.*)$/, async (route) => { expect(route.request().method()).toBe('GET'); const url = new URL(route.request().url()); - const nameFilter = (url.searchParams.get('name') || '*').replaceAll('*', '').toLowerCase(); + const nameFilter = (url.searchParams.get('name') || '*').replace(/\*/g, '').toLowerCase(); const users = Object.values(validUsers) .filter((user) => { @@ -122,8 +122,7 @@ async function basicInit(page: Page) { // Update a user await page.route(/\/api\/user\/(\d+)$/, async (route) => { - expect(route.request().method()).toBe('PUT'); - const userReq = route.request().postDataJSON(); + const method = route.request().method(); const userId = route.request().url().split('/').pop(); if (!userId) { @@ -137,6 +136,18 @@ async function basicInit(page: Page) { return; } + if (method === 'DELETE') { + const [currentEmail, currentUser] = currentEntry; + delete validUsers[currentEmail]; + if (loggedInUser?.id === currentUser.id) { + loggedInUser = undefined; + } + await route.fulfill({ json: { message: 'user deleted successfully' } }); + return; + } + + expect(method).toBe('PUT'); + const userReq = route.request().postDataJSON(); const [currentEmail, currentUser] = currentEntry; const updatedUser: User = { ...currentUser, From 17ed2e4ff58c3cfa5b432d7148368bc7a7f100ce Mon Sep 17 00:00:00 2001 From: cjmot <146262493+cjmot@users.noreply.github.com> Date: Sat, 21 Feb 2026 17:44:41 -0700 Subject: [PATCH 41/42] fix admin test error --- tests/adminFunctions.spec.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/adminFunctions.spec.ts b/tests/adminFunctions.spec.ts index ef5f62e83..8ebab8d18 100644 --- a/tests/adminFunctions.spec.ts +++ b/tests/adminFunctions.spec.ts @@ -91,7 +91,8 @@ test('admin can filter users list by name and email', async ({ page }) => { await page.getByPlaceholder('Filter users').fill('a@jwt.com'); await page.getByRole('button', { name: 'Submit' }).click(); - await expect(page.getByRole('cell', { name: 'a@jwt.com' })).toBeVisible(); + const adminEmailCells = await page.getByRole('cell', { name: 'a@jwt.com' }).count(); + expect(adminEmailCells).toBeGreaterThanOrEqual(1); await expect(page.getByRole('cell', { name: 'f@jwt.com' })).toHaveCount(0); }); From 79f50343c75be496a4a1b448d08dbc8a7e022abb Mon Sep 17 00:00:00 2001 From: cjmot <146262493+cjmot@users.noreply.github.com> Date: Sat, 21 Feb 2026 17:47:25 -0700 Subject: [PATCH 42/42] update tests ci to only trigger on pull requests to main or workflow dispatch --- .github/workflows/tests.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 830fa5f13..6d25cf469 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,9 +1,6 @@ name: tests on: - push: - branches-ignore: - - main pull_request: branches: - main