diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f6faf44..d2a7d18 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -64,7 +64,6 @@ jobs: - run: pnpm install --frozen-lockfile - run: pnpm --filter api exec prisma migrate deploy - run: pnpm --filter api test - - run: pnpm --filter api test:bdd build: runs-on: ubuntu-latest diff --git a/README.md b/README.md index f02b09b..73e604c 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Monorepo pnpm workspaces : -- `apps/api` — backend Express/TypeScript (squelette générique : healthcheck, config env, Prisma non modélisé, tests Mocha + Cucumber/BDD) +- `apps/api` — backend Express/TypeScript (squelette générique : healthcheck, config env, Prisma non modélisé, tests Mocha) - `apps/web` — frontend React/Vite/TypeScript, prêt à être embarqué par Capacitor plus tard. Page de connexion/inscription en place ; le reste est encore un squelette générique. - `packages/shared` — code partagé entre `api` et `web` : schémas zod (`signupSchema`, @@ -108,38 +108,12 @@ pnpm dev:web pnpm lint # Biome (lint + format check) pnpm lint:fix # Biome --write pnpm test # tests unitaires/intégration (Mocha, apps/api) -pnpm --filter api test:bdd # tests d'intégration BDD (Cucumber/Gherkin, apps/api) pnpm --filter web e2e # tests e2e (Cypress, démarre le serveur dev automatiquement) pnpm build # build de tous les workspaces ``` La CI GitHub Actions (`.github/workflows/ci.yml`) exécute quatre jobs indépendants (`lint`, `test`, `build`, `e2e`) en parallèle, sur chaque push (toutes branches) et sur chaque PR vers `main` — pas de chaînage entre eux, chacun apparaît comme son propre check. Voir aussi [Déploiement](#déploiement) pour le pipeline de release (`.github/workflows/release.yml`). -### Cucumber (apps/api) - -Tests d'intégration lisibles en Gherkin, en complément de Mocha (qui reste pour les -tests unitaires purs) : - -- `apps/api/features/*.feature` — scénarios en Given/When/Then (`health.feature` sert - d'exemple) -- `apps/api/features/step-definitions/*.steps.ts` — implémentation des steps -- `apps/api/features/support/world.ts` — contexte partagé entre les steps d'un - scénario (instancie l'app Express in-process via `createApp()`, comme le fait déjà - supertest côté Mocha — pas besoin de lancer un vrai serveur) -- `apps/api/cucumber.cjs` — config (extension `.cjs` volontaire, voir la remarque - TypeScript/ESM ci-dessous) - -Pour ajouter un scénario : écrire le `.feature`, lancer `pnpm --filter api test:bdd`, -implémenter les steps manquants (Cucumber affiche des snippets tout prêts pour ceux -qui n'existent pas encore). - -> **Piège TypeScript/ESM à connaître** (déjà rencontré avec `cypress.config.ts`) : -> les fichiers de config d'outils tiers qui font du chargement dynamique de TS -> (`cucumber.cjs`, `cypress.config.ts`…) sont sensibles au `"type": "module"` du -> `package.json`. `cucumber.cjs` évite le problème *pour sa propre config* en étant -> explicitement CommonJS ; les steps/world restent en `.ts` ESM classique et sont -> chargés via `tsx` (`NODE_OPTIONS=--import=tsx`, voir le script `test:bdd`). - ## Déploiement Une seule image Docker (`apps/api/Dockerfile`) sert à la fois l'API et le frontend @@ -204,14 +178,14 @@ encore implémenté). > concrètement (`argon2.hash(...)` dans un `node -e`) avant de merger, un `pnpm build` > qui passe ne suffit pas à détecter un crash runtime. -Les tests (Mocha + Cucumber) tournent avec un coût argon2 réduit +Les tests (Mocha) tournent avec un coût argon2 réduit (`NODE_ENV=test`, voir `auth.service.ts`) — le coût par défaut est volontairement élevé (sécurité), ce qui rendrait la suite de tests lente/instable sinon. La CI provisionne un vrai Postgres de service (`.github/workflows/ci.yml`) et exécute `prisma migrate deploy` avant les tests. > **Les tests automatisés et `pnpm dev:api` partagent la même base Postgres locale.** -> Lancer `pnpm test`/`test:bdd` **vide `user_profiles`/`house`** (`TRUNCATE ... CASCADE`, +> Lancer `pnpm test` **vide `user_profiles`/`house`** (`TRUNCATE ... CASCADE`, > voir `test-support/reset-db.ts`) — si tu es en train de tester manuellement à la main > (via le navigateur ou curl) contre le serveur de dev, un run de tests en parallèle > efface tes données de test sans prévenir. Pas un bug, juste à savoir. @@ -371,12 +345,10 @@ page fetch son propre profil frais (`apiClient.me()`) au montage, et `AuthContext.refreshUser()` (nouveau) est appelé après une sauvegarde réussie du régime pour que le reste de l'app reste cohérent aussi. -Tests Cypress (`apps/web/cypress/e2e/`) : `smoke.cy.ts` + `auth.cy.ts` + -`home-planning.cy.ts` + `onboarding.cy.ts` + `household.cy.ts` mockent l'API via -`cy.intercept` plutôt que de dépendre d'un vrai backend — le job e2e de la CI ne -provisionne pas de Postgres/API, seulement le serveur de dev Vite. Le comportement -réel de l'API est couvert par les suites Mocha/Cucumber d'`apps/api` (contre une -vraie base). +Tests Cypress (`apps/web/cypress/e2e/*.cy.ts`) : mockent l'API via `cy.intercept` +plutôt que de dépendre d'un vrai backend — le job e2e de la CI ne provisionne pas de +Postgres/API, seulement le serveur de dev Vite. Le comportement réel de l'API est +couvert par la suite Mocha d'`apps/api` (contre une vraie base). > **Cypress ne peut pas tourner en local dans un environnement Windows sandboxé** : > Chromium/Electron headless plante au lancement du process GPU @@ -425,10 +397,5 @@ en ajouter une est une question de fichier de locale, pas de code. Détail : ## Données de test (faker.js) `apps/api` utilise [`@faker-js/faker`](https://fakerjs.dev/) pour toutes les données -de test dans `test/auth.test.ts` (Mocha) et le "bruit" (prénom/nom de remplissage) -des steps Cucumber — jamais de nom/email qui ressemble à une vraie personne en dur -dans un fixture. Les valeurs *littérales* des scénarios `.feature` eux-mêmes -(ex. `alice@example.com`) restent volontairement statiques : c'est le point des -scénarios Gherkin lisibles (exemples illustratifs conventionnels en BDD, pas des -données réelles) — seules les données de remplissage hors du texte lisible du -scénario sont générées. +de test dans `test/*.test.ts` (Mocha) — jamais de nom/email qui ressemble à une +vraie personne en dur dans un fixture. diff --git a/apps/api/cucumber.cjs b/apps/api/cucumber.cjs deleted file mode 100644 index 5a06f40..0000000 --- a/apps/api/cucumber.cjs +++ /dev/null @@ -1,11 +0,0 @@ -// Explicit .cjs extension (not .js) so this loads as CommonJS regardless of -// the "type": "module" in package.json — avoids the same ESM/CJS config -// loader mismatch that broke apps/web/cypress.config.ts earlier. -module.exports = { - default: { - paths: ["features/**/*.feature"], - import: ["features/**/*.ts"], - format: ["progress-bar"], - formatOptions: { snippetInterface: "async-await" }, - }, -}; diff --git a/apps/api/features/auth.feature b/apps/api/features/auth.feature deleted file mode 100644 index c31a7b2..0000000 --- a/apps/api/features/auth.feature +++ /dev/null @@ -1,50 +0,0 @@ -Feature: Account creation and login - As a new user - I want to create a profile and log in - So that I can access my household's batch-cooking planning - - Scenario: A visitor creates a new profile - When I sign up with the following details: - | firstName | Alice | - | lastName | Martin | - | email | alice@example.com | - | password | correct-horse-battery-staple | - Then the response status should be 201 - And I am authenticated as "alice@example.com" - - Scenario: A visitor cannot sign up twice with the same email - Given a profile already exists with email "alice@example.com" - When I sign up with the following details: - | firstName | Alice | - | lastName | Martin | - | email | alice@example.com | - | password | correct-horse-battery-staple | - Then the response status should be 409 - And the response error code should be "EMAIL_ALREADY_IN_USE" - - Scenario: A registered user logs in with correct credentials - Given a profile already exists with email "alice@example.com" and password "correct-horse-battery-staple" - When I log in with email "alice@example.com" and password "correct-horse-battery-staple" - Then the response status should be 200 - And I am authenticated as "alice@example.com" - - Scenario: A registered user cannot log in with the wrong password - Given a profile already exists with email "alice@example.com" and password "correct-horse-battery-staple" - When I log in with email "alice@example.com" and password "wrong-password" - Then the response status should be 401 - And the response error code should be "INVALID_CREDENTIALS" - - Scenario: A signed-in user cannot delete their account with the wrong password - Given a profile already exists with email "alice@example.com" and password "correct-horse-battery-staple" - And I log in with email "alice@example.com" and password "correct-horse-battery-staple" - When I delete my account with password "wrong-password" - Then the response status should be 401 - And the response error code should be "INVALID_CREDENTIALS" - And I am authenticated as "alice@example.com" - - Scenario: A signed-in user deletes their account - Given a profile already exists with email "alice@example.com" and password "correct-horse-battery-staple" - And I log in with email "alice@example.com" and password "correct-horse-battery-staple" - When I delete my account with password "correct-horse-battery-staple" - Then the response status should be 204 - And I am no longer authenticated diff --git a/apps/api/features/health.feature b/apps/api/features/health.feature deleted file mode 100644 index 717dafe..0000000 --- a/apps/api/features/health.feature +++ /dev/null @@ -1,12 +0,0 @@ -Feature: API health check - As a monitoring service - I want to query the API - So that I can verify it is up and responding correctly - - Scenario: The API is available - When I send a GET request to "/health" - Then the response status should be 200 - And the response body should be: - """ - { "status": "ok" } - """ diff --git a/apps/api/features/household.feature b/apps/api/features/household.feature deleted file mode 100644 index bb1e874..0000000 --- a/apps/api/features/household.feature +++ /dev/null @@ -1,67 +0,0 @@ -Feature: Household - As a signed-in user - I want to name my household, invite others to it, and manage its members - So that my whole household can share the same planning - - Scenario: A visitor without a session cannot read the household - When I send a GET request to "/house/current" - Then the response status should be 401 - And the response error code should be "NOT_AUTHENTICATED" - - Scenario: A signed-in user creates a household - Given a profile already exists with email "alice@example.com" and password "correct-horse-battery-staple" - And I log in with email "alice@example.com" and password "correct-horse-battery-staple" - When I create a household named "Chez Alice" - Then the response status should be 201 - And my household should be named "Chez Alice" - - Scenario: A signed-in user renames their household - Given a profile already exists with email "alice@example.com" and password "correct-horse-battery-staple" - And I log in with email "alice@example.com" and password "correct-horse-battery-staple" - And I have a household named "Foyer de test" - When I rename my household to "Chez les Martin" - Then the response status should be 200 - And my household should be named "Chez les Martin" - - Scenario: A second user joins a household using its invite code - Given a profile already exists with email "alice@example.com" and password "correct-horse-battery-staple" - And I log in with email "alice@example.com" and password "correct-horse-battery-staple" - And I have a household named "Chez Alice" - And a profile already exists with email "bob@example.com" and password "correct-horse-battery-staple" - When the second user logs in with email "bob@example.com" and password "correct-horse-battery-staple" - And the second user joins my household using its invite code - Then the second user's response status should be 200 - And the second user should be a member of my household - - Scenario: A non-admin member cannot delete the household - Given a profile already exists with email "alice@example.com" and password "correct-horse-battery-staple" - And I log in with email "alice@example.com" and password "correct-horse-battery-staple" - And I have a household named "Chez Alice" - And a profile already exists with email "bob@example.com" and password "correct-horse-battery-staple" - And the second user logs in with email "bob@example.com" and password "correct-horse-battery-staple" - And the second user joins my household using its invite code - When the second user tries to delete the household - Then the second user's response status should be 403 - And the second user's response error code should be "NOT_HOUSE_ADMIN" - - Scenario: Adminship transfers to the remaining member when the admin leaves - Given a profile already exists with email "alice@example.com" and password "correct-horse-battery-staple" - And I log in with email "alice@example.com" and password "correct-horse-battery-staple" - And I have a household named "Chez Alice" - And a profile already exists with email "bob@example.com" and password "correct-horse-battery-staple" - And the second user logs in with email "bob@example.com" and password "correct-horse-battery-staple" - And the second user joins my household using its invite code - When I leave the household - Then the response status should be 204 - And the second user should be the household's admin - - Scenario: The admin removes a member - Given a profile already exists with email "alice@example.com" and password "correct-horse-battery-staple" - And I log in with email "alice@example.com" and password "correct-horse-battery-staple" - And I have a household named "Chez Alice" - And a profile already exists with email "bob@example.com" and password "correct-horse-battery-staple" - And the second user logs in with email "bob@example.com" and password "correct-horse-battery-staple" - And the second user joins my household using its invite code - When I remove the second user from my household - Then the response status should be 200 - And the second user should have no household diff --git a/apps/api/features/planning.feature b/apps/api/features/planning.feature deleted file mode 100644 index 5810a91..0000000 --- a/apps/api/features/planning.feature +++ /dev/null @@ -1,24 +0,0 @@ -Feature: Household weekly planning - As a signed-in user - I want to see my household's current planning - So that I know what meals are planned this week - - Scenario: A visitor without a session cannot view the planning - When I request the current planning - Then the response status should be 401 - And the response error code should be "NOT_AUTHENTICATED" - - Scenario: A signed-in user with no planning yet sees an empty state - Given a profile already exists with email "alice@example.com" and password "correct-horse-battery-staple" - And I log in with email "alice@example.com" and password "correct-horse-battery-staple" - When I request the current planning - Then the response status should be 200 - And the current planning response should be empty - - Scenario: A signed-in user sees their household's current planning - Given a profile already exists with email "alice@example.com" and password "correct-horse-battery-staple" - And I log in with email "alice@example.com" and password "correct-horse-battery-staple" - And my household has a planning covering today with recipe "Ratatouille" on "monday" for "dinner" - When I request the current planning - Then the response status should be 200 - And the current planning response should include recipe "Ratatouille" on "monday" for "dinner" diff --git a/apps/api/features/preferences.feature b/apps/api/features/preferences.feature deleted file mode 100644 index 17cd1b9..0000000 --- a/apps/api/features/preferences.feature +++ /dev/null @@ -1,23 +0,0 @@ -Feature: User preferences (theme) - As a signed-in user - I want to choose a light, dark, or system theme - So that the app matches how I like to read it - - Scenario: A visitor without a session cannot read preferences - When I send a GET request to "/preferences" - Then the response status should be 401 - And the response error code should be "NOT_AUTHENTICATED" - - Scenario: A signed-in user with no preferences yet defaults to SYSTEM - Given a profile already exists with email "alice@example.com" and password "correct-horse-battery-staple" - And I log in with email "alice@example.com" and password "correct-horse-battery-staple" - When I request my preferences - Then the response status should be 200 - And my theme preference should be "SYSTEM" - - Scenario: A signed-in user sets their theme preference - Given a profile already exists with email "alice@example.com" and password "correct-horse-battery-staple" - And I log in with email "alice@example.com" and password "correct-horse-battery-staple" - When I set my theme preference to "DARK" - Then the response status should be 200 - And my theme preference should be "DARK" diff --git a/apps/api/features/profile.feature b/apps/api/features/profile.feature deleted file mode 100644 index deca688..0000000 --- a/apps/api/features/profile.feature +++ /dev/null @@ -1,28 +0,0 @@ -Feature: Profile regime and allergens - As a signed-in user - I want to set my dietary regime and allergens/intolerances - So that the household's meal planning can account for them later - - Scenario: A visitor without a session cannot set a regime - When I send a PATCH request to "/profile/diet" with body: - """ - { "dietId": 1 } - """ - Then the response status should be 401 - And the response error code should be "NOT_AUTHENTICATED" - - Scenario: A signed-in user sets their regime to a valid, seeded diet - Given a profile already exists with email "alice@example.com" and password "correct-horse-battery-staple" - And I log in with email "alice@example.com" and password "correct-horse-battery-staple" - When I set my regime to "Végétarien" - Then the response status should be 200 - And my profile's regime should be "Végétarien" - - Scenario: A signed-in user selects allergens, then replaces the selection - Given a profile already exists with email "alice@example.com" and password "correct-horse-battery-staple" - And I log in with email "alice@example.com" and password "correct-horse-battery-staple" - When I set my allergens to "Arachides, Gluten" - Then the response status should be 200 - And my selected allergens should be "Arachides, Gluten" - When I set my allergens to "Lait" - Then my selected allergens should be "Lait" diff --git a/apps/api/features/recipe.feature b/apps/api/features/recipe.feature deleted file mode 100644 index 508fb03..0000000 --- a/apps/api/features/recipe.feature +++ /dev/null @@ -1,59 +0,0 @@ -Feature: Recipe catalog - As a signed-in user - I want to browse, create and manage recipes - So that the household can plan meals from a shared catalog - - Scenario: A visitor without a session cannot browse the catalog - When I request the recipe catalog - Then the response status should be 401 - And the response error code should be "NOT_AUTHENTICATED" - - Scenario: A signed-in user creates a recipe with an ingredient and a step - Given a profile already exists with email "alice@example.com" and password "correct-horse-battery-staple" - And I log in with email "alice@example.com" and password "correct-horse-battery-staple" - When I create a recipe named "Ratatouille" with ingredient "Tomate" and step "Couper les légumes" - Then the response status should be 201 - And the created recipe should have ingredient "Tomate" and step "Couper les légumes" - - Scenario: Creating a recipe with an unknown ingredient is rejected - Given a profile already exists with email "alice@example.com" and password "correct-horse-battery-staple" - And I log in with email "alice@example.com" and password "correct-horse-battery-staple" - When I create a recipe named "Ratatouille" with unknown ingredient id 999999 and step "Couper les légumes" - Then the response status should be 404 - And the response error code should be "INGREDIENT_NOT_FOUND" - - Scenario: A signed-in user sees their own recipe in the "perso" tab - Given a profile already exists with email "alice@example.com" and password "correct-horse-battery-staple" - And I log in with email "alice@example.com" and password "correct-horse-battery-staple" - And a recipe named "Ratatouille" already exists with ingredient "Tomate" and step "Couper les légumes" - When I request the recipe catalog tab "perso" - Then the response status should be 200 - And the recipe catalog response should include "Ratatouille" - - Scenario: A signed-in user favorites a recipe and finds it in the "favoris" tab - Given a profile already exists with email "alice@example.com" and password "correct-horse-battery-staple" - And I log in with email "alice@example.com" and password "correct-horse-battery-staple" - And a recipe named "Ratatouille" already exists with ingredient "Tomate" and step "Couper les légumes" - When I favorite the recipe named "Ratatouille" - And I request the recipe catalog tab "favoris" - Then the response status should be 200 - And the recipe catalog response should include "Ratatouille" - - Scenario: Only a recipe's author can edit it - Given a profile already exists with email "alice@example.com" and password "correct-horse-battery-staple" - And I log in with email "alice@example.com" and password "correct-horse-battery-staple" - And a public recipe named "Ratatouille" already exists with ingredient "Tomate" and step "Couper les légumes" - And a profile already exists with email "bob@example.com" and password "correct-horse-battery-staple" - And the second user logs in with email "bob@example.com" and password "correct-horse-battery-staple" - When the second user tries to modify the recipe named "Ratatouille" - Then the second user's response status should be 403 - And the second user's response error code should be "NOT_RECIPE_AUTHOR" - - Scenario: Deleting a recipe still used by a planning item is rejected - Given a profile already exists with email "alice@example.com" and password "correct-horse-battery-staple" - And I log in with email "alice@example.com" and password "correct-horse-battery-staple" - And a recipe named "Ratatouille" already exists with ingredient "Tomate" and step "Couper les légumes" - And my household has a planning that uses the recipe named "Ratatouille" - When I delete the recipe named "Ratatouille" - Then the response status should be 409 - And the response error code should be "RECIPE_IN_USE" diff --git a/apps/api/features/reference.feature b/apps/api/features/reference.feature deleted file mode 100644 index 10b7718..0000000 --- a/apps/api/features/reference.feature +++ /dev/null @@ -1,14 +0,0 @@ -Feature: Reference data (diets, allergens) - As a visitor filling in the signup wizard, or a signed-in user editing their profile - I want to read the list of dietary regimes and allergens - So that I can pick from them — before an account necessarily exists - - Scenario: A visitor without a session can read the list of dietary regimes - When I send a GET request to "/reference/diets" - Then the response status should be 200 - And the reference list response should include "Végétarien" - - Scenario: A visitor without a session can read the list of allergens - When I send a GET request to "/reference/allergies" - Then the response status should be 200 - And the reference list response should include "Arachides" diff --git a/apps/api/features/step-definitions/auth.steps.ts b/apps/api/features/step-definitions/auth.steps.ts deleted file mode 100644 index 9f5a737..0000000 --- a/apps/api/features/step-definitions/auth.steps.ts +++ /dev/null @@ -1,67 +0,0 @@ -import assert from "node:assert/strict"; -import type { DataTable } from "@cucumber/cucumber"; -import { Given, Then, When } from "@cucumber/cucumber"; -import { faker } from "@faker-js/faker"; -import { signup } from "../../src/modules/auth/auth.service.js"; -import type { CustomWorld } from "../support/world.js"; - -// firstName/lastName/password below are filler for background state the -// scenario doesn't actually read (only the emails in the .feature file are -// part of what's being tested) — faker-generated rather than hardcoded so -// no test fixture ever looks like a real person's data. - -Given("a profile already exists with email {string}", async (email: string) => { - await signup({ - firstName: faker.person.firstName(), - lastName: faker.person.lastName(), - email, - password: faker.internet.password({ length: 16 }), - }); -}); - -Given( - "a profile already exists with email {string} and password {string}", - async (email: string, password: string) => { - await signup({ - firstName: faker.person.firstName(), - lastName: faker.person.lastName(), - email, - password, - }); - }, -); - -When("I sign up with the following details:", async function (this: CustomWorld, table: DataTable) { - const details = table.rowsHash(); - this.response = await this.agent.post("/auth/signup").send({ - firstName: details.firstName, - lastName: details.lastName, - email: details.email, - password: details.password, - }); -}); - -When( - "I log in with email {string} and password {string}", - async function (this: CustomWorld, email: string, password: string) { - this.response = await this.agent.post("/auth/login").send({ email, password }); - }, -); - -When( - "I delete my account with password {string}", - async function (this: CustomWorld, password: string) { - this.response = await this.agent.delete("/auth/me").send({ password }); - }, -); - -Then("I am authenticated as {string}", async function (this: CustomWorld, email: string) { - const res = await this.agent.get("/auth/me"); - assert.equal(res.status, 200); - assert.equal(res.body.email, email); -}); - -Then("I am no longer authenticated", async function (this: CustomWorld) { - const res = await this.agent.get("/auth/me"); - assert.equal(res.status, 401); -}); diff --git a/apps/api/features/step-definitions/health.steps.ts b/apps/api/features/step-definitions/health.steps.ts deleted file mode 100644 index 052fe87..0000000 --- a/apps/api/features/step-definitions/health.steps.ts +++ /dev/null @@ -1,38 +0,0 @@ -import assert from "node:assert/strict"; -import { ErrorCode } from "@batch-cooking/shared"; -import { Then, When } from "@cucumber/cucumber"; -import request from "supertest"; -import type { CustomWorld } from "../support/world.js"; - -When("I send a GET request to {string}", async function (this: CustomWorld, path: string) { - this.response = await request(this.app).get(path); -}); - -When( - "I send a PATCH request to {string} with body:", - async function (this: CustomWorld, path: string, body: string) { - this.response = await request(this.app).patch(path).send(JSON.parse(body)); - }, -); - -Then("the response status should be {int}", function (this: CustomWorld, status: number) { - assert.equal(this.response.status, status); -}); - -Then("the response body should be:", function (this: CustomWorld, expectedJson: string) { - assert.deepEqual(this.response.body, JSON.parse(expectedJson)); -}); - -// Generic enough to be reused by any feature asserting on the shared -// ApiErrorResponse contract's `code` field — not health-specific, but this -// file is where the other generic response-assertion steps already live. -// -// `code` here is the enum *member name* (readable in the .feature file, -// e.g. "EMAIL_ALREADY_IN_USE") — ErrorCode[name] resolves it to the real -// numeric value via TypeScript's reverse enum lookup, so this never -// compares against a hardcoded number. -Then("the response error code should be {string}", function (this: CustomWorld, code: string) { - const expected = ErrorCode[code as keyof typeof ErrorCode]; - assert.notEqual(expected, undefined, `Unknown ErrorCode member: "${code}"`); - assert.equal(this.response.body.code, expected); -}); diff --git a/apps/api/features/step-definitions/household.steps.ts b/apps/api/features/step-definitions/household.steps.ts deleted file mode 100644 index 9e48e0d..0000000 --- a/apps/api/features/step-definitions/household.steps.ts +++ /dev/null @@ -1,90 +0,0 @@ -import assert from "node:assert/strict"; -import { ErrorCode } from "@batch-cooking/shared"; -import { Given, Then, When } from "@cucumber/cucumber"; -import type { CustomWorld } from "../support/world.js"; - -Given("I have a household named {string}", async function (this: CustomWorld, name: string) { - const res = await this.agent.post("/house").send({ name }); - assert.equal(res.status, 201, JSON.stringify(res.body)); -}); - -When("I create a household named {string}", async function (this: CustomWorld, name: string) { - this.response = await this.agent.post("/house").send({ name }); -}); - -When("I rename my household to {string}", async function (this: CustomWorld, name: string) { - this.response = await this.agent.patch("/house/current").send({ name }); -}); - -When("I leave the household", async function (this: CustomWorld) { - this.response = await this.agent.post("/house/leave"); -}); - -When("I remove the second user from my household", async function (this: CustomWorld) { - const secondMe = await this.secondAgent.get("/auth/me"); - this.response = await this.agent.delete(`/house/members/${secondMe.body.id}`); -}); - -Then("my household should be named {string}", async function (this: CustomWorld, name: string) { - const res = await this.agent.get("/house/current"); - assert.equal(res.body.name, name); -}); - -// --- Steps involving a second, independently signed-in user --------------- -// The first ("a profile already exists with email ...") step is reused -// as-is for the second user too — it just inserts a row, agent-agnostic. - -When( - "the second user logs in with email {string} and password {string}", - async function (this: CustomWorld, email: string, password: string) { - this.secondResponse = await this.secondAgent.post("/auth/login").send({ email, password }); - }, -); - -When( - "the second user joins my household using its invite code", - async function (this: CustomWorld) { - const house = await this.agent.get("/house/current"); - this.secondResponse = await this.secondAgent - .post("/house/join") - .send({ inviteCode: house.body.inviteCode }); - }, -); - -When("the second user tries to delete the household", async function (this: CustomWorld) { - this.secondResponse = await this.secondAgent.delete("/house/current"); -}); - -Then( - "the second user's response status should be {int}", - function (this: CustomWorld, status: number) { - assert.equal(this.secondResponse.status, status); - }, -); - -Then( - "the second user's response error code should be {string}", - function (this: CustomWorld, code: string) { - const expected = ErrorCode[code as keyof typeof ErrorCode]; - assert.notEqual(expected, undefined, `Unknown ErrorCode member: "${code}"`); - assert.equal(this.secondResponse.body.code, expected); - }, -); - -Then("the second user should be a member of my household", async function (this: CustomWorld) { - const house = await this.agent.get("/house/current"); - const secondMe = await this.secondAgent.get("/auth/me"); - const memberIds = (house.body.members as Array<{ id: number }>).map((member) => member.id); - assert.ok(memberIds.includes(secondMe.body.id)); -}); - -Then("the second user should be the household's admin", async function (this: CustomWorld) { - const secondMe = await this.secondAgent.get("/auth/me"); - const house = await this.secondAgent.get("/house/current"); - assert.equal(house.body.adminId, secondMe.body.id); -}); - -Then("the second user should have no household", async function (this: CustomWorld) { - const secondMe = await this.secondAgent.get("/auth/me"); - assert.equal(secondMe.body.houseId, null); -}); diff --git a/apps/api/features/step-definitions/planning.steps.ts b/apps/api/features/step-definitions/planning.steps.ts deleted file mode 100644 index c71ec7f..0000000 --- a/apps/api/features/step-definitions/planning.steps.ts +++ /dev/null @@ -1,60 +0,0 @@ -import assert from "node:assert/strict"; -import { Given, Then, When } from "@cucumber/cucumber"; -import { prisma } from "../../src/db/prisma.js"; -import { TEST_REFERENCE_DATE } from "../../test-support/reference-date.js"; -import type { CustomWorld } from "../support/world.js"; - -/** `GET /planning` takes `?date=` explicitly — this scenario wording ("the current planning") maps to the fixed test "today" (see `TEST_REFERENCE_DATE`). */ -When("I request the current planning", async function (this: CustomWorld) { - this.response = await this.agent - .get("/planning") - .query({ date: TEST_REFERENCE_DATE.toISODate() }); -}); - -Then("the current planning response should be empty", function (this: CustomWorld) { - assert.equal(this.response.body, null); -}); - -// Creates the planning/recipe rows directly via Prisma rather than through -// the API — there's no "create a planning" endpoint yet (see -// specs/batch-cooking-architecture.md, "Calcul batch-cooking" is still -// TODO), so this is the only way to get a household into a state where it -// has one. A household is no longer created implicitly at signup, so this -// step creates one via `POST /house` first — the scenario never names it -// explicitly, its name doesn't matter here. -Given( - "my household has a planning covering today with recipe {string} on {string} for {string}", - async function (this: CustomWorld, recipeName: string, weekDay: string, meal: string) { - const houseRes = await this.agent.post("/house").send({ name: "Foyer de test" }); - const houseId: number = houseRes.body.id; - - const recipe = await prisma.recipe.create({ - data: { name: recipeName, authorId: houseRes.body.adminId }, - }); - const planning = await prisma.planning.create({ - data: { - houseId, - startDate: TEST_REFERENCE_DATE.minus({ days: 2 }).toJSDate(), - finishDate: TEST_REFERENCE_DATE.plus({ days: 2 }).toJSDate(), - }, - }); - await prisma.planningItem.create({ - data: { planningId: planning.id, weekDay, meal, recipeId: recipe.id }, - }); - }, -); - -Then( - "the current planning response should include recipe {string} on {string} for {string}", - function (this: CustomWorld, recipeName: string, weekDay: string, meal: string) { - const items = this.response.body.items as Array<{ - weekDay: string; - meal: string; - recipe: { name: string }; - }>; - const item = items.find((i) => i.recipe.name === recipeName); - assert.ok(item, `expected an item with recipe "${recipeName}", got ${JSON.stringify(items)}`); - assert.equal(item.weekDay, weekDay); - assert.equal(item.meal, meal); - }, -); diff --git a/apps/api/features/step-definitions/preferences.steps.ts b/apps/api/features/step-definitions/preferences.steps.ts deleted file mode 100644 index 3062682..0000000 --- a/apps/api/features/step-definitions/preferences.steps.ts +++ /dev/null @@ -1,15 +0,0 @@ -import assert from "node:assert/strict"; -import { Then, When } from "@cucumber/cucumber"; -import type { CustomWorld } from "../support/world.js"; - -When("I request my preferences", async function (this: CustomWorld) { - this.response = await this.agent.get("/preferences"); -}); - -When("I set my theme preference to {string}", async function (this: CustomWorld, theme: string) { - this.response = await this.agent.patch("/preferences").send({ theme }); -}); - -Then("my theme preference should be {string}", function (this: CustomWorld, theme: string) { - assert.equal(this.response.body.theme, theme); -}); diff --git a/apps/api/features/step-definitions/profile.steps.ts b/apps/api/features/step-definitions/profile.steps.ts deleted file mode 100644 index 1503d92..0000000 --- a/apps/api/features/step-definitions/profile.steps.ts +++ /dev/null @@ -1,54 +0,0 @@ -import assert from "node:assert/strict"; -import { Then, When } from "@cucumber/cucumber"; -import { getEnglishKey } from "../../src/db/catalog-en-keys.js"; -import { prisma } from "../../src/db/prisma.js"; -import type { CustomWorld } from "../support/world.js"; - -/** Splits a comma-separated list of names from a `.feature` string into trimmed, non-empty parts. */ -function splitNames(names: string): string[] { - return names - .split(",") - .map((name) => name.trim()) - .filter(Boolean); -} - -/** - * Resolves allergen names (as written in a `.feature` file, e.g. - * "Arachides") to their Allergy id — scenarios still name allergens by their - * French label for readability, so this slugifies before matching against - * `Category.key` (see reference.service.ts for why the key lives on - * Category, not Allergy). - */ -async function allergyIdsFor(names: string[]): Promise { - const allergies = await prisma.allergy.findMany({ include: { category: true } }); - return names.map((name) => { - const key = getEnglishKey(name); - const match = allergies.find((allergy) => allergy.category.key === key); - if (!match) throw new Error(`No seeded allergen named "${name}"`); - return match.id; - }); -} - -When("I set my regime to {string}", async function (this: CustomWorld, dietName: string) { - const diet = await prisma.diet.findFirstOrThrow({ where: { key: getEnglishKey(dietName) } }); - this.response = await this.agent.patch("/profile/diet").send({ dietId: diet.id }); -}); - -Then( - "my profile's regime should be {string}", - async function (this: CustomWorld, dietName: string) { - const diet = await prisma.diet.findFirstOrThrow({ where: { key: getEnglishKey(dietName) } }); - assert.equal(this.response.body.dietId, diet.id); - }, -); - -When("I set my allergens to {string}", async function (this: CustomWorld, names: string) { - const allergyIds = await allergyIdsFor(splitNames(names)); - this.response = await this.agent.patch("/profile/allergies").send({ allergyIds }); -}); - -Then("my selected allergens should be {string}", async function (this: CustomWorld, names: string) { - const expected = (await allergyIdsFor(splitNames(names))).sort(); - const actual = [...this.response.body].sort(); - assert.deepEqual(actual, expected); -}); diff --git a/apps/api/features/step-definitions/recipe.steps.ts b/apps/api/features/step-definitions/recipe.steps.ts deleted file mode 100644 index b18ccbc..0000000 --- a/apps/api/features/step-definitions/recipe.steps.ts +++ /dev/null @@ -1,168 +0,0 @@ -import assert from "node:assert/strict"; -import { Given, Then, When } from "@cucumber/cucumber"; -import { getEnglishKey } from "../../src/db/catalog-en-keys.js"; -import { prisma } from "../../src/db/prisma.js"; -import { TEST_REFERENCE_DATE } from "../../test-support/reference-date.js"; -import type { CustomWorld } from "../support/world.js"; - -/** - * Resolves a reference ingredient by its seeded French name — every - * scenario below names an ingredient by its `reference-seed-data.ts` name, - * never a raw id or its slug `key` directly, so this slugifies before - * matching. - */ -async function findIngredientId(name: string): Promise { - const ingredient = await prisma.ingredient.findFirstOrThrow({ - where: { key: getEnglishKey(name) }, - }); - return ingredient.id; -} - -When("I request the recipe catalog", async function (this: CustomWorld) { - this.response = await this.agent.get("/recipes"); -}); - -When("I request the recipe catalog tab {string}", async function (this: CustomWorld, tab: string) { - this.response = await this.agent.get("/recipes").query({ tab }); -}); - -Then( - "the recipe catalog response should include {string}", - function (this: CustomWorld, name: string) { - const names = (this.response.body as Array<{ name: string }>).map((recipe) => recipe.name); - assert.ok(names.includes(name), `expected ${JSON.stringify(names)} to include "${name}"`); - }, -); - -When( - "I create a recipe named {string} with ingredient {string} and step {string}", - async function (this: CustomWorld, name: string, ingredientName: string, step: string) { - const ingredientId = await findIngredientId(ingredientName); - this.response = await this.agent.post("/recipes").send({ - name, - dietIds: [], - ingredients: [{ ingredientId, quantity: 1, unit: "unité" }], - steps: [{ description: step }], - }); - }, -); - -When( - "I create a recipe named {string} with unknown ingredient id {int} and step {string}", - async function (this: CustomWorld, name: string, unknownIngredientId: number, step: string) { - this.response = await this.agent.post("/recipes").send({ - name, - dietIds: [], - ingredients: [{ ingredientId: unknownIngredientId, quantity: 1, unit: "unité" }], - steps: [{ description: step }], - }); - }, -); - -Then( - "the created recipe should have ingredient {string} and step {string}", - function (this: CustomWorld, ingredientName: string, step: string) { - const body = this.response.body as { - ingredients: Array<{ ingredient: { key: string } }>; - steps: Array<{ description: string }>; - }; - const expectedKey = getEnglishKey(ingredientName); - assert.ok(body.ingredients.some((line) => line.ingredient.key === expectedKey)); - assert.ok(body.steps.some((s) => s.description === step)); - }, -); - -// Created directly via Prisma (with a nested ingredient + step), not through -// the API — same rationale as `planning.steps.ts`'s equivalent "already -// exists" step: this is background state the scenario needs in place before -// its actual `When`, not the behavior under test. `authorId` is the -// currently-logged-in agent's own profile — `visibility` defaults to -// `PERSONAL` (schema.prisma), matching a recipe this agent just created for -// themselves. -Given( - "a recipe named {string} already exists with ingredient {string} and step {string}", - async function (this: CustomWorld, name: string, ingredientName: string, step: string) { - const ingredientId = await findIngredientId(ingredientName); - const me = await this.agent.get("/auth/me"); - await prisma.recipe.create({ - data: { - name, - authorId: me.body.id, - ingredients: { create: [{ ingredientId, quantity: 1, unit: "unité" }] }, - steps: { create: [{ description: step, order: 0 }] }, - }, - }); - }, -); - -// Same as above but `visibility: PUBLIC` — needed for scenarios where a -// *second* user must be able to see (though not necessarily edit) the -// recipe, e.g. the "only the author can edit" scenario: a `PERSONAL` -// recipe would 404 for anyone else before the authorship check even runs -// (see `recipe.service.ts`'s `canView`). -Given( - "a public recipe named {string} already exists with ingredient {string} and step {string}", - async function (this: CustomWorld, name: string, ingredientName: string, step: string) { - const ingredientId = await findIngredientId(ingredientName); - const me = await this.agent.get("/auth/me"); - await prisma.recipe.create({ - data: { - name, - authorId: me.body.id, - visibility: "PUBLIC", - ingredients: { create: [{ ingredientId, quantity: 1, unit: "unité" }] }, - steps: { create: [{ description: step, order: 0 }] }, - }, - }); - }, -); - -// Distinct from `planning.steps.ts`'s "my household has a planning covering -// today with recipe {string}..." — that step always creates a *new* recipe -// row with the given name, which wouldn't exercise the actual `RECIPE_IN_USE` -// check against a recipe this feature already created. This step instead -// looks up the already-existing recipe by name and points the planning item -// at its real id. -Given( - "my household has a planning that uses the recipe named {string}", - async function (this: CustomWorld, recipeName: string) { - const houseRes = await this.agent.post("/house").send({ name: "Foyer de test" }); - const houseId: number = houseRes.body.id; - const recipe = await prisma.recipe.findFirstOrThrow({ where: { name: recipeName } }); - - const planning = await prisma.planning.create({ - data: { - houseId, - startDate: TEST_REFERENCE_DATE.minus({ days: 2 }).toJSDate(), - finishDate: TEST_REFERENCE_DATE.plus({ days: 2 }).toJSDate(), - }, - }); - await prisma.planningItem.create({ - data: { planningId: planning.id, weekDay: "lundi", meal: "diner", recipeId: recipe.id }, - }); - }, -); - -When("I delete the recipe named {string}", async function (this: CustomWorld, name: string) { - const recipe = await prisma.recipe.findFirstOrThrow({ where: { name } }); - this.response = await this.agent.delete(`/recipes/${recipe.id}`); -}); - -When("I favorite the recipe named {string}", async function (this: CustomWorld, name: string) { - const recipe = await prisma.recipe.findFirstOrThrow({ where: { name } }); - this.response = await this.agent.post(`/recipes/${recipe.id}/favorite`); -}); - -When( - "the second user tries to modify the recipe named {string}", - async function (this: CustomWorld, name: string) { - const ingredientId = await findIngredientId("Tomate"); - const recipe = await prisma.recipe.findFirstOrThrow({ where: { name } }); - this.secondResponse = await this.secondAgent.patch(`/recipes/${recipe.id}`).send({ - name, - dietIds: [], - ingredients: [{ ingredientId, quantity: 1, unit: "unité" }], - steps: [{ description: "Hack" }], - }); - }, -); diff --git a/apps/api/features/step-definitions/reference.steps.ts b/apps/api/features/step-definitions/reference.steps.ts deleted file mode 100644 index 82fb3c7..0000000 --- a/apps/api/features/step-definitions/reference.steps.ts +++ /dev/null @@ -1,20 +0,0 @@ -import assert from "node:assert/strict"; -import { Then } from "@cucumber/cucumber"; -import { getEnglishKey } from "../../src/db/catalog-en-keys.js"; -import type { CustomWorld } from "../support/world.js"; - -// The feature file still names an item by its French label, for -// readability — the response itself carries only the slug `key` (see -// reference.service.ts), so this slugifies the expected label before -// comparing. -Then( - "the reference list response should include {string}", - function (this: CustomWorld, name: string) { - const keys = (this.response.body as Array<{ key: string }>).map((item) => item.key); - const expectedKey = getEnglishKey(name); - assert.ok( - keys.includes(expectedKey), - `expected ${JSON.stringify(keys)} to include "${expectedKey}"`, - ); - }, -); diff --git a/apps/api/features/support/hooks.ts b/apps/api/features/support/hooks.ts deleted file mode 100644 index 57b15a7..0000000 --- a/apps/api/features/support/hooks.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Before, setDefaultTimeout } from "@cucumber/cucumber"; -import { resetDatabase } from "../../test-support/reset-db.js"; - -// Integration tests hitting a real Postgres + argon2 need more than -// Cucumber's 5s default, especially on a cold Prisma connection. -setDefaultTimeout(10_000); - -Before(async () => { - await resetDatabase(); -}); diff --git a/apps/api/features/support/world.ts b/apps/api/features/support/world.ts deleted file mode 100644 index 69b84e6..0000000 --- a/apps/api/features/support/world.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { type IWorldOptions, World, setWorldConstructor } from "@cucumber/cucumber"; -import type { Express } from "express"; -import request from "supertest"; -import { createApp } from "../../src/app.js"; - -// Fresh Express app per scenario (in-process, via supertest — no server to -// spin up/tear down) plus the last HTTP response, available to every step. -// `agent` persists cookies across requests within a scenario (needed for -// "sign up then check I'm authenticated" style flows). -export class CustomWorld extends World { - app: Express; - agent: ReturnType; - response!: request.Response; - /** A second, independent session (own cookie jar) — only used by scenarios needing two distinct signed-in users, e.g. household invites/admin transfer/member removal. */ - secondAgent: ReturnType; - secondResponse!: request.Response; - - constructor(options: IWorldOptions) { - super(options); - this.app = createApp(); - this.agent = request.agent(this.app); - this.secondAgent = request.agent(this.app); - } -} - -setWorldConstructor(CustomWorld); diff --git a/apps/api/package.json b/apps/api/package.json index 283cf99..8ccf511 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -8,7 +8,6 @@ "build": "tsc -p tsconfig.json", "start": "node dist/server.js", "test": "cross-env NODE_ENV=test mocha", - "test:bdd": "cross-env NODE_ENV=test NODE_OPTIONS=--import=tsx cucumber-js", "prisma:generate": "prisma generate", "prisma:migrate": "prisma migrate dev", "prisma:seed": "prisma db seed", @@ -31,7 +30,6 @@ "zod": "^3.23.8" }, "devDependencies": { - "@cucumber/cucumber": "^13.2.1", "@faker-js/faker": "^10.6.0", "@types/express": "^4.17.21", "@types/jsonwebtoken": "^9.0.10", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bf6ace9..fa447c2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -51,9 +51,6 @@ importers: specifier: ^3.23.8 version: 3.25.76 devDependencies: - '@cucumber/cucumber': - specifier: ^13.2.1 - version: 13.2.1 '@faker-js/faker': specifier: ^10.6.0 version: 10.6.0 @@ -365,74 +362,6 @@ packages: resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==, tarball: https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz} engines: {node: '>=0.1.90'} - '@cucumber/ci-environment@14.0.0': - resolution: {integrity: sha512-CJbjPPGuk1fArPRVKB6FU2q9FHxOQOeq7IEJcB2NLNhOhV97uazLxvwD5ucAJb/flky+czOLhvaYaRAF6l5QYQ==, tarball: https://registry.npmjs.org/@cucumber/ci-environment/-/ci-environment-14.0.0.tgz} - - '@cucumber/cucumber-expressions@20.0.0': - resolution: {integrity: sha512-t2FBLKuU0U1nP5FM8pHiVonYcXVm07fvXr/H9osdvrjcLXSWc5OCbOOqV/k5S56w/YndPv1Sv2/m/x1KBYvIlA==, tarball: https://registry.npmjs.org/@cucumber/cucumber-expressions/-/cucumber-expressions-20.0.0.tgz} - - '@cucumber/cucumber@13.2.1': - resolution: {integrity: sha512-Km3mLbZKOE/TlR9ExGWcG7PwOG1ArMt/R6BexrMhGA8pLGaLCWYISTHStpftLuuhVKvVd3RO5M/pfARKyvcyWg==, tarball: https://registry.npmjs.org/@cucumber/cucumber/-/cucumber-13.2.1.tgz} - engines: {node: 22 || 24 || >=26} - hasBin: true - - '@cucumber/gherkin-streams@7.0.1': - resolution: {integrity: sha512-8W1lmof0hbQ1HgOEpPCkz1KCFaM6MfA7n7rr6vX/7ffgUQ0saOAwapKSVj7P68Aht0K9XqHaw8BDLtqaK/jRIg==, tarball: https://registry.npmjs.org/@cucumber/gherkin-streams/-/gherkin-streams-7.0.1.tgz} - hasBin: true - peerDependencies: - '@cucumber/gherkin': '>=22.0.0' - '@cucumber/message-streams': '>=4.0.0' - '@cucumber/messages': '>=17.1.1' - - '@cucumber/gherkin-utils@12.0.1': - resolution: {integrity: sha512-vImHbmTzvGcZP4SFSbx7P6janHZN+BqGWXc3EIQ7UeYMeDzwV9ybSlRfpECV340pxKYZyMTtuSCP3CDXfuWCQw==, tarball: https://registry.npmjs.org/@cucumber/gherkin-utils/-/gherkin-utils-12.0.1.tgz} - hasBin: true - - '@cucumber/gherkin@41.0.0': - resolution: {integrity: sha512-pKGx1EzNjtWbpw74kEevKDMj71dF3ZSaFJpLYuWVvRZKe+Cwoq5iEkuMaELIg1jxIu8jH/A2HPMpMR8UBvdG0w==, tarball: https://registry.npmjs.org/@cucumber/gherkin/-/gherkin-41.0.0.tgz} - - '@cucumber/gherkin@42.0.0': - resolution: {integrity: sha512-kBcv+NV4FGQYX6NIsSCjsjaX8MsRdEH559BQ9xEFPgkLQX/Z//JZrY94fpjxW6quo4V5kxlzFiiVC5xouF9Akg==, tarball: https://registry.npmjs.org/@cucumber/gherkin/-/gherkin-42.0.0.tgz} - - '@cucumber/html-formatter@24.1.0': - resolution: {integrity: sha512-5TBLnBT+tIvtamw/jtblBVgzQ2/ckd+md8I0rwkEk29vFMCF68jNwhyONGq6leUYMq4kVF+KdFhE8xGrSc3kJw==, tarball: https://registry.npmjs.org/@cucumber/html-formatter/-/html-formatter-24.1.0.tgz} - peerDependencies: - '@cucumber/messages': '>=18' - - '@cucumber/junit-xml-formatter@0.14.0': - resolution: {integrity: sha512-uDuJySsUr1b1VEAERC+YywvVhygBgYIAMyfSMzLZ3LrourudaWZIhfTND4uLNkRZZQcPr6IYv+qj5TP8RTJJ+g==, tarball: https://registry.npmjs.org/@cucumber/junit-xml-formatter/-/junit-xml-formatter-0.14.0.tgz} - peerDependencies: - '@cucumber/messages': '*' - - '@cucumber/message-streams@5.0.1': - resolution: {integrity: sha512-MXsD7ZAWWAiWMrn3Lzq2nwu9DJpPbbvdqXj2ot1BSM2gXnoSvg8d0pc6PzS9pI02swMSn/KN11mTdF5ScE7X0Q==, tarball: https://registry.npmjs.org/@cucumber/message-streams/-/message-streams-5.0.1.tgz} - peerDependencies: - '@cucumber/messages': '>=17.1.1' - - '@cucumber/messages@33.0.4': - resolution: {integrity: sha512-i6P1a0bnmhecOHfvIW0rhMxv/gMKfBKwDMxmD9/Uo1HSqpQ17ocHms1JwWW6uTMLAopqqWlcz7l6Pax+qUOTzg==, tarball: https://registry.npmjs.org/@cucumber/messages/-/messages-33.0.4.tgz} - - '@cucumber/messages@34.2.0': - resolution: {integrity: sha512-6X6T1TApmbQNqxC0Oh3GcnLU+gfE5fp+cEXE/ml6+Ldx76Q6BDmkgM5vagSSDXP+vetPV2Fb0kWVeP7QIR6+Aw==, tarball: https://registry.npmjs.org/@cucumber/messages/-/messages-34.2.0.tgz} - - '@cucumber/pretty-formatter@4.0.0': - resolution: {integrity: sha512-vWKHUfjMphtbeHHlQBZ1gQzPL3/HE/O2dNnpBqEOIDwvhp7tKvqSe8kscp2H7pArbxN6euEpR5JbstJdzo3iyg==, tarball: https://registry.npmjs.org/@cucumber/pretty-formatter/-/pretty-formatter-4.0.0.tgz} - peerDependencies: - '@cucumber/messages': '*' - - '@cucumber/query@16.0.0': - resolution: {integrity: sha512-CtGBHLc92y1RNogXGOFVF7so+XdLR5rVuJGsS6nH7yLeayyYhdV8lYW/LG8R05cm4irG/RO6Wn5I2CAgxMhmwQ==, tarball: https://registry.npmjs.org/@cucumber/query/-/query-16.0.0.tgz} - peerDependencies: - '@cucumber/messages': '*' - - '@cucumber/query@16.1.1': - resolution: {integrity: sha512-SBaP4Lc7xv55jY78Q8raoxvbBIPGhQKrui/Tq+l6jYBl1alV0TG1sW8TRtk9W7RQl27nVJo9DyyvASp374L9Tg==, tarball: https://registry.npmjs.org/@cucumber/query/-/query-16.1.1.tgz} - peerDependencies: - '@cucumber/messages': '*' - - '@cucumber/tag-expressions@11.0.0': - resolution: {integrity: sha512-7Uo6dYST8xZbHwwemXCt7Kv80Yh/SE85DyOed1/FTwxRXs3NYVOCm6e/h8DxlhTGIpD6rYXfpY3nHnIXAFMBlw==, tarball: https://registry.npmjs.org/@cucumber/tag-expressions/-/tag-expressions-11.0.0.tgz} - '@cypress/request@3.0.10': resolution: {integrity: sha512-hauBrOdvu08vOsagkZ/Aju5XuiZx6ldsLfByg1htFeldhex+PeMrYauANzFsMJeAA0+dyPLbDoX2OYuvVoLDkQ==, tarball: https://registry.npmjs.org/@cypress/request/-/request-3.0.10.tgz} engines: {node: '>= 6'} @@ -1029,10 +958,6 @@ packages: '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==, tarball: https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz} - '@teppeis/multimaps@3.0.0': - resolution: {integrity: sha512-ID7fosbc50TbT0MK0EG12O+gAP3W3Aa/Pz4DaTtQtEvlc9Odaqi0de+xuZ7Li2GtK4HzEX7IuRWS/JmZLksR3Q==, tarball: https://registry.npmjs.org/@teppeis/multimaps/-/multimaps-3.0.0.tgz} - engines: {node: '>=14'} - '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==, tarball: https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz} @@ -1092,9 +1017,6 @@ packages: '@types/node@22.20.1': resolution: {integrity: sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==, tarball: https://registry.npmjs.org/@types/node/-/node-22.20.1.tgz} - '@types/normalize-package-data@2.4.4': - resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==, tarball: https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz} - '@types/prop-types@15.7.15': resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==, tarball: https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz} @@ -1169,10 +1091,6 @@ packages: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==, tarball: https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz} engines: {node: '>=8'} - ansi-regex@6.3.0: - resolution: {integrity: sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==, tarball: https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz} - engines: {node: '>=12'} - ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==, tarball: https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz} engines: {node: '>=8'} @@ -1215,9 +1133,6 @@ packages: resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==, tarball: https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz} engines: {node: '>=0.8'} - assertion-error-formatter@3.0.0: - resolution: {integrity: sha512-6YyAVLrEze0kQ7CmJfUgrLHb+Y7XghmL2Ie7ijVa2Y9ynP3LV+VDiwFk62Dn0qtqbmY0BT0ss6p1xxpiF2PYbQ==, tarball: https://registry.npmjs.org/assertion-error-formatter/-/assertion-error-formatter-3.0.0.tgz} - assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==, tarball: https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz} engines: {node: '>=12'} @@ -1297,9 +1212,6 @@ packages: buffer-equal-constant-time@1.0.1: resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==, tarball: https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz} - buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==, tarball: https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz} - buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==, tarball: https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz} @@ -1398,10 +1310,6 @@ packages: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==, tarball: https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz} engines: {node: '>= 0.8'} - commander@15.0.0: - resolution: {integrity: sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==, tarball: https://registry.npmjs.org/commander/-/commander-15.0.0.tgz} - engines: {node: '>=22.12.0'} - commander@6.2.1: resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==, tarball: https://registry.npmjs.org/commander/-/commander-6.2.1.tgz} engines: {node: '>= 6'} @@ -1541,10 +1449,6 @@ packages: dezalgo@1.0.4: resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==, tarball: https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz} - diff@4.0.4: - resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==, tarball: https://registry.npmjs.org/diff/-/diff-4.0.4.tgz} - engines: {node: '>=0.3.1'} - diff@5.2.2: resolution: {integrity: sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A==, tarball: https://registry.npmjs.org/diff/-/diff-5.2.2.tgz} engines: {node: '>=0.3.1'} @@ -1586,9 +1490,6 @@ packages: resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==, tarball: https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz} engines: {node: '>=8.6'} - error-stack-parser@2.1.4: - resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==, tarball: https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz} - es-define-property@1.0.1: resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==, tarball: https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz} engines: {node: '>= 0.4'} @@ -1678,10 +1579,6 @@ packages: resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==, tarball: https://registry.npmjs.org/figures/-/figures-3.2.0.tgz} engines: {node: '>=8'} - figures@6.1.0: - resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==, tarball: https://registry.npmjs.org/figures/-/figures-6.1.0.tgz} - engines: {node: '>=18'} - fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==, tarball: https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz} engines: {node: '>=8'} @@ -1690,10 +1587,6 @@ packages: resolution: {integrity: sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==, tarball: https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz} engines: {node: '>= 0.8'} - find-up-simple@1.0.1: - resolution: {integrity: sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==, tarball: https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz} - engines: {node: '>=18'} - find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==, tarball: https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz} engines: {node: '>=10'} @@ -1800,10 +1693,6 @@ packages: engines: {node: '>=12'} 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 - global-directory@4.0.1: - resolution: {integrity: sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==, tarball: https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz} - engines: {node: '>=18'} - global-dirs@3.0.1: resolution: {integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==, tarball: https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz} engines: {node: '>=10'} @@ -1815,10 +1704,6 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==, tarball: https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz} - has-ansi@6.0.2: - resolution: {integrity: sha512-vAyM+6+jAYwSwz0/M0jYKfU9AvAMCz0kH791RsUhvMKGUHXled/3FjcQB3YiQ4Astj5srHdb6B2FHGIfZkOQNg==, tarball: https://registry.npmjs.org/has-ansi/-/has-ansi-6.0.2.tgz} - engines: {node: '>=18'} - has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==, tarball: https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz} engines: {node: '>=8'} @@ -1842,10 +1727,6 @@ packages: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==, tarball: https://registry.npmjs.org/he/-/he-1.2.0.tgz} hasBin: true - hosted-git-info@9.0.3: - resolution: {integrity: sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg==, tarball: https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.3.tgz} - engines: {node: ^20.17.0 || >=22.9.0} - html-parse-stringify@4.0.1: resolution: {integrity: sha512-0zHsZJrK7S3K2aucXWL6ycoYJ/iNtIcFHC/nYQgFklPtrv5LpJctIiSCroWZWeuoXvuyFdzp6KzjJQ+OT5MfFw==, tarball: https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-4.0.1.tgz} @@ -1891,14 +1772,6 @@ packages: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==, tarball: https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz} engines: {node: '>=8'} - indent-string@5.0.0: - resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==, tarball: https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz} - engines: {node: '>=12'} - - index-to-position@1.2.0: - resolution: {integrity: sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==, tarball: https://registry.npmjs.org/index-to-position/-/index-to-position-1.2.0.tgz} - engines: {node: '>=18'} - inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==, tarball: https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz} 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. @@ -1910,10 +1783,6 @@ packages: resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==, tarball: https://registry.npmjs.org/ini/-/ini-2.0.0.tgz} engines: {node: '>=10'} - ini@4.1.1: - resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==, tarball: https://registry.npmjs.org/ini/-/ini-4.1.1.tgz} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==, tarball: https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz} engines: {node: '>= 0.10'} @@ -1938,10 +1807,6 @@ packages: resolution: {integrity: sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==, tarball: https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz} engines: {node: '>=10'} - is-installed-globally@1.0.0: - resolution: {integrity: sha512-K55T22lfpQ63N4KEN57jZUAaAYqYHEe8veb/TycJRk9DdSCLLcovXz/mL6mOnhQaZsQGwPhuFopdQIlqGSEjiQ==, tarball: https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-1.0.0.tgz} - engines: {node: '>=18'} - is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==, tarball: https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz} engines: {node: '>=0.12.0'} @@ -1950,10 +1815,6 @@ packages: resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==, tarball: https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz} engines: {node: '>=8'} - is-path-inside@4.0.0: - resolution: {integrity: sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==, tarball: https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz} - engines: {node: '>=12'} - is-plain-obj@2.1.0: resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==, tarball: https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz} engines: {node: '>=8'} @@ -1969,10 +1830,6 @@ packages: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==, tarball: https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz} engines: {node: '>=10'} - is-unicode-supported@2.1.0: - resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==, tarball: https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz} - engines: {node: '>=18'} - isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==, tarball: https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz} @@ -2026,9 +1883,6 @@ packages: jws@4.0.1: resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==, tarball: https://registry.npmjs.org/jws/-/jws-4.0.1.tgz} - knuth-shuffle-seeded@1.0.6: - resolution: {integrity: sha512-9pFH0SplrfyKyojCLxZfMcvkhf5hH0d+UwR9nTVJ/DDQJGuzcXjTwB7TP7sDfehSudlGGaOLblmEWqv04ERVWg==, tarball: https://registry.npmjs.org/knuth-shuffle-seeded/-/knuth-shuffle-seeded-1.0.6.tgz} - lazy-ass@1.6.0: resolution: {integrity: sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==, tarball: https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz} engines: {node: '> 0.8'} @@ -2064,18 +1918,9 @@ packages: lodash.isstring@4.0.1: resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==, tarball: https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz} - lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==, tarball: https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz} - - lodash.mergewith@4.6.2: - resolution: {integrity: sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==, tarball: https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz} - lodash.once@4.1.1: resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==, tarball: https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz} - lodash.sortby@4.7.0: - resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==, tarball: https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz} - lodash@4.18.1: resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==, tarball: https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz} @@ -2094,10 +1939,6 @@ packages: loupe@3.2.1: resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==, tarball: https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz} - lru-cache@11.5.2: - resolution: {integrity: sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==, tarball: https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz} - engines: {node: 20 || >=22} - lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==, tarball: https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz} @@ -2153,11 +1994,6 @@ packages: engines: {node: '>=4.0.0'} hasBin: true - mime@4.1.0: - resolution: {integrity: sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw==, tarball: https://registry.npmjs.org/mime/-/mime-4.1.0.tgz} - engines: {node: '>=16'} - hasBin: true - mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==, tarball: https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz} engines: {node: '>=6'} @@ -2230,10 +2066,6 @@ packages: engines: {node: '>=6'} hasBin: true - normalize-package-data@8.0.0: - resolution: {integrity: sha512-RWk+PI433eESQ7ounYxIp67CYuVsS1uYSonX3kA6ps/3LWfjVQa/ptEg6Y3T6uAMq1mWpX9PQ+qx+QaHpsc7gQ==, tarball: https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-8.0.0.tgz} - engines: {node: ^20.17.0 || >=22.9.0} - normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==, tarball: https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz} engines: {node: '>=0.10.0'} @@ -2280,14 +2112,6 @@ packages: resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==, tarball: https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz} engines: {node: '>=10'} - pad-right@0.2.2: - resolution: {integrity: sha512-4cy8M95ioIGolCoMmm2cMntGR1lPLEbOMzOKu8bzjuJP6JpzEMQcDHmh7hHLYGgob+nKe1YHFMaG4V59HQa89g==, tarball: https://registry.npmjs.org/pad-right/-/pad-right-0.2.2.tgz} - engines: {node: '>=0.10.0'} - - parse-json@8.3.0: - resolution: {integrity: sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==, tarball: https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz} - engines: {node: '>=18'} - parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==, tarball: https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz} engines: {node: '>= 0.8'} @@ -2352,9 +2176,6 @@ packages: resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==, tarball: https://registry.npmjs.org/process/-/process-0.11.10.tgz} engines: {node: '>= 0.6.0'} - property-expr@2.0.6: - resolution: {integrity: sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==, tarball: https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz} - proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==, tarball: https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz} engines: {node: '>= 0.10'} @@ -2439,14 +2260,6 @@ packages: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==, tarball: https://registry.npmjs.org/react/-/react-18.3.1.tgz} engines: {node: '>=0.10.0'} - read-package-up@12.0.0: - resolution: {integrity: sha512-Q5hMVBYur/eQNWDdbF4/Wqqr9Bjvtrw2kjGxxBbKLbx8bVCL8gcArjTy8zDUuLGQicftpMuU0riQNcAsbtOVsw==, tarball: https://registry.npmjs.org/read-package-up/-/read-package-up-12.0.0.tgz} - engines: {node: '>=20'} - - read-pkg@10.1.0: - resolution: {integrity: sha512-I8g2lArQiP78ll51UeMZojewtYgIRCKCWqZEgOO8c/uefTI+XDXvCSXu3+YNUaTNvZzobrL5+SqHjBrByRRTdg==, tarball: https://registry.npmjs.org/read-pkg/-/read-pkg-10.1.0.tgz} - engines: {node: '>=20'} - readable-stream@3.6.2: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==, tarball: https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz} engines: {node: '>= 6'} @@ -2459,17 +2272,6 @@ packages: resolution: {integrity: sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==, tarball: https://registry.npmjs.org/readdirp/-/readdirp-5.1.1.tgz} engines: {node: '>= 20.19.0'} - regexp-match-indices@1.0.2: - resolution: {integrity: sha512-DwZuAkt8NF5mKwGGER1EGh2PRqyvhRhhLviH+R8y8dIuaQROlUfXjt4s9ZTXstIsSkptf06BSvwcEmmfheJJWQ==, tarball: https://registry.npmjs.org/regexp-match-indices/-/regexp-match-indices-1.0.2.tgz} - - regexp-tree@0.1.27: - resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==, tarball: https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz} - hasBin: true - - repeat-string@1.6.1: - resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==, tarball: https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz} - engines: {node: '>=0.10'} - request-progress@3.0.0: resolution: {integrity: sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==, tarball: https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz} @@ -2511,9 +2313,6 @@ packages: scheduler@0.23.2: resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==, tarball: https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz} - seed-random@2.2.0: - resolution: {integrity: sha512-34EQV6AAHQGhoc0tn/96a9Fsi6v2xdqe/dMUwljGRaFOzR3EgRmECvD0O8vi8X+/uQ50LGHfkNu/Eue5TPKZkQ==, tarball: https://registry.npmjs.org/seed-random/-/seed-random-2.2.0.tgz} - semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==, tarball: https://registry.npmjs.org/semver/-/semver-6.3.1.tgz} hasBin: true @@ -2582,25 +2381,6 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==, tarball: https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz} engines: {node: '>=0.10.0'} - source-map-support@0.5.21: - resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==, tarball: https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz} - - source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==, tarball: https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz} - engines: {node: '>=0.10.0'} - - spdx-correct@3.2.0: - resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==, tarball: https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz} - - spdx-exceptions@2.5.0: - resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==, tarball: https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz} - - spdx-expression-parse@3.0.1: - resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==, tarball: https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz} - - spdx-license-ids@3.0.23: - resolution: {integrity: sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==, tarball: https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz} - split@0.3.3: resolution: {integrity: sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==, tarball: https://registry.npmjs.org/split/-/split-0.3.3.tgz} @@ -2609,9 +2389,6 @@ packages: engines: {node: '>=0.10.0'} hasBin: true - stackframe@1.3.4: - resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==, tarball: https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz} - start-server-and-test@2.1.5: resolution: {integrity: sha512-A/SbXpgXE25ScSkpLLqvGvVZT0ykN6+AzS8tVqMBCTxbJy2Nwuen59opT+afalK5aS+AuQmZs0EsLwjnuDN+/g==, tarball: https://registry.npmjs.org/start-server-and-test/-/start-server-and-test-2.1.5.tgz} engines: {node: '>=16'} @@ -2624,10 +2401,6 @@ packages: stream-combiner@0.0.4: resolution: {integrity: sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==, tarball: https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz} - string-argv@0.3.2: - resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==, tarball: https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz} - engines: {node: '>=0.6.19'} - string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==, tarball: https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz} engines: {node: '>=8'} @@ -2655,10 +2428,6 @@ packages: resolution: {integrity: sha512-oK8WG9diS3DlhdUkcFn4tkNIiIbBx9lI2ClF8K+b2/m8Eyv47LSawxUzZQSNKUrVb2KsqeTDCcjAAVPYaSLVTA==, tarball: https://registry.npmjs.org/supertest/-/supertest-7.2.2.tgz} engines: {node: '>=14.18.0'} - supports-color@11.0.0: - resolution: {integrity: sha512-/zyImLdxhdygBIaVX0xTlQhKaCDLCrm665aqHk8xqK/Pa6k61fL6gwQGQq1k31yNyz6x55PppQgF2DMyPQa5xw==, tarball: https://registry.npmjs.org/supports-color/-/supports-color-11.0.0.tgz} - engines: {node: '>=22'} - supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==, tarball: https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz} engines: {node: '>=8'} @@ -2667,10 +2436,6 @@ packages: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==, tarball: https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz} engines: {node: '>=10'} - tagged-tag@1.0.0: - resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==, tarball: https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz} - engines: {node: '>=20'} - tar@6.2.1: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==, tarball: https://registry.npmjs.org/tar/-/tar-6.2.1.tgz} engines: {node: '>=10'} @@ -2682,9 +2447,6 @@ packages: through@2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==, tarball: https://registry.npmjs.org/through/-/through-2.3.8.tgz} - tiny-case@1.0.3: - resolution: {integrity: sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==, tarball: https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz} - tldts-core@6.1.86: resolution: {integrity: sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==, tarball: https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz} @@ -2704,9 +2466,6 @@ packages: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==, tarball: https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz} engines: {node: '>=0.6'} - toposort@2.0.2: - resolution: {integrity: sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==, tarball: https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz} - tough-cookie@5.1.2: resolution: {integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==, tarball: https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz} engines: {node: '>=16'} @@ -2736,18 +2495,6 @@ packages: resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==, tarball: https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz} engines: {node: '>=10'} - type-fest@2.19.0: - resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==, tarball: https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz} - engines: {node: '>=12.20'} - - type-fest@4.41.0: - resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==, tarball: https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz} - engines: {node: '>=16'} - - type-fest@5.8.0: - resolution: {integrity: sha512-YGYEVz3Fm5iy/AybuA0oyNFq7H4CgQNfRp/qfe8nurE1kuCeNm3/vfm9X4Mtl+qLyaKJUh5xrFZwogr41SMjYA==, tarball: https://registry.npmjs.org/type-fest/-/type-fest-5.8.0.tgz} - engines: {node: '>=20'} - type-is@1.6.18: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==, tarball: https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz} engines: {node: '>= 0.6'} @@ -2760,10 +2507,6 @@ packages: undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==, tarball: https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz} - unicorn-magic@0.4.0: - resolution: {integrity: sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==, tarball: https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.4.0.tgz} - engines: {node: '>=20'} - universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==, tarball: https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz} engines: {node: '>= 10.0.0'} @@ -2787,9 +2530,6 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - util-arity@1.1.0: - resolution: {integrity: sha512-kkyIsXKwemfSy8ZEoaIz06ApApnWsk5hQO0vLjZS6UkBiGiW++Jsyb8vSBoc0WKlffGoGs5yYy/j5pp8zckrFA==, tarball: https://registry.npmjs.org/util-arity/-/util-arity-1.1.0.tgz} - util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==, tarball: https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz} @@ -2802,9 +2542,6 @@ packages: deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). hasBin: true - validate-npm-package-license@3.0.4: - resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==, tarball: https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz} - vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==, tarball: https://registry.npmjs.org/vary/-/vary-1.1.2.tgz} engines: {node: '>= 0.8'} @@ -2877,10 +2614,6 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==, tarball: https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz} - xmlbuilder@15.1.1: - resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==, tarball: https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz} - engines: {node: '>=8.0'} - y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==, tarball: https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz} engines: {node: '>=10'} @@ -2891,11 +2624,6 @@ packages: yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==, tarball: https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz} - yaml@2.9.0: - resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==, tarball: https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz} - engines: {node: '>= 14.6'} - hasBin: true - yargs-parser@20.2.9: resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==, tarball: https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz} engines: {node: '>=10'} @@ -2915,9 +2643,6 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==, tarball: https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz} engines: {node: '>=10'} - yup@1.7.1: - resolution: {integrity: sha512-GKHFX2nXul2/4Dtfxhozv701jLQHdf6J34YDh2cEkpqoo8le5Mg6/LrdseVLrFarmFygZTlfIhHx/QKfb/QWXw==, tarball: https://registry.npmjs.org/yup/-/yup-1.7.1.tgz} - zod@3.25.76: resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==, tarball: https://registry.npmjs.org/zod/-/zod-3.25.76.tgz} @@ -2944,7 +2669,7 @@ snapshots: '@babel/types': 7.29.8 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -3028,7 +2753,7 @@ snapshots: '@babel/parser': 7.29.8 '@babel/template': 7.29.7 '@babel/types': 7.29.8 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -3075,112 +2800,6 @@ snapshots: '@colors/colors@1.5.0': optional: true - '@cucumber/ci-environment@14.0.0': {} - - '@cucumber/cucumber-expressions@20.0.0': - dependencies: - regexp-match-indices: 1.0.2 - - '@cucumber/cucumber@13.2.1': - dependencies: - '@cucumber/ci-environment': 14.0.0 - '@cucumber/cucumber-expressions': 20.0.0 - '@cucumber/gherkin': 42.0.0 - '@cucumber/gherkin-streams': 7.0.1(@cucumber/gherkin@42.0.0)(@cucumber/message-streams@5.0.1(@cucumber/messages@34.2.0))(@cucumber/messages@34.2.0) - '@cucumber/gherkin-utils': 12.0.1 - '@cucumber/html-formatter': 24.1.0(@cucumber/messages@34.2.0) - '@cucumber/junit-xml-formatter': 0.14.0(@cucumber/messages@34.2.0) - '@cucumber/message-streams': 5.0.1(@cucumber/messages@34.2.0) - '@cucumber/messages': 34.2.0 - '@cucumber/pretty-formatter': 4.0.0(@cucumber/messages@34.2.0) - '@cucumber/tag-expressions': 11.0.0 - assertion-error-formatter: 3.0.0 - cli-table3: 0.6.5 - commander: 15.0.0 - debug: 4.4.3(supports-color@11.0.0) - error-stack-parser: 2.1.4 - figures: 6.1.0 - has-ansi: 6.0.2 - indent-string: 5.0.0 - is-installed-globally: 1.0.0 - knuth-shuffle-seeded: 1.0.6 - lodash.merge: 4.6.2 - lodash.mergewith: 4.6.2 - luxon: 3.7.2 - read-package-up: 12.0.0 - semver: 7.8.5 - string-argv: 0.3.2 - supports-color: 11.0.0 - type-fest: 5.8.0 - util-arity: 1.1.0 - yaml: 2.9.0 - yup: 1.7.1 - - '@cucumber/gherkin-streams@7.0.1(@cucumber/gherkin@42.0.0)(@cucumber/message-streams@5.0.1(@cucumber/messages@34.2.0))(@cucumber/messages@34.2.0)': - dependencies: - '@cucumber/gherkin': 42.0.0 - '@cucumber/message-streams': 5.0.1(@cucumber/messages@34.2.0) - '@cucumber/messages': 34.2.0 - commander: 15.0.0 - source-map-support: 0.5.21 - - '@cucumber/gherkin-utils@12.0.1': - dependencies: - '@cucumber/gherkin': 41.0.0 - '@cucumber/messages': 33.0.4 - '@teppeis/multimaps': 3.0.0 - commander: 15.0.0 - source-map-support: 0.5.21 - - '@cucumber/gherkin@41.0.0': - dependencies: - '@cucumber/messages': 33.0.4 - - '@cucumber/gherkin@42.0.0': - dependencies: - '@cucumber/messages': 34.2.0 - - '@cucumber/html-formatter@24.1.0(@cucumber/messages@34.2.0)': - dependencies: - '@cucumber/messages': 34.2.0 - - '@cucumber/junit-xml-formatter@0.14.0(@cucumber/messages@34.2.0)': - dependencies: - '@cucumber/messages': 34.2.0 - '@cucumber/query': 16.1.1(@cucumber/messages@34.2.0) - '@teppeis/multimaps': 3.0.0 - luxon: 3.7.2 - xmlbuilder: 15.1.1 - - '@cucumber/message-streams@5.0.1(@cucumber/messages@34.2.0)': - dependencies: - '@cucumber/messages': 34.2.0 - mime: 4.1.0 - - '@cucumber/messages@33.0.4': {} - - '@cucumber/messages@34.2.0': {} - - '@cucumber/pretty-formatter@4.0.0(@cucumber/messages@34.2.0)': - dependencies: - '@cucumber/messages': 34.2.0 - '@cucumber/query': 16.0.0(@cucumber/messages@34.2.0) - luxon: 3.7.2 - - '@cucumber/query@16.0.0(@cucumber/messages@34.2.0)': - dependencies: - '@cucumber/messages': 34.2.0 - '@teppeis/multimaps': 3.0.0 - lodash.sortby: 4.7.0 - - '@cucumber/query@16.1.1(@cucumber/messages@34.2.0)': - dependencies: - '@cucumber/messages': 34.2.0 - '@teppeis/multimaps': 3.0.0 - lodash.sortby: 4.7.0 - - '@cucumber/tag-expressions@11.0.0': {} - '@cypress/request@3.0.10': dependencies: aws-sign2: 0.7.0 @@ -3582,8 +3201,6 @@ snapshots: '@standard-schema/spec@1.1.0': {} - '@teppeis/multimaps@3.0.0': {} - '@types/babel__core@7.20.5': dependencies: '@babel/parser': 7.29.8 @@ -3659,8 +3276,6 @@ snapshots: dependencies: undici-types: 6.21.0 - '@types/normalize-package-data@2.4.4': {} - '@types/prop-types@15.7.15': {} '@types/qs@6.15.1': {} @@ -3733,7 +3348,7 @@ snapshots: agent-base@6.0.2: dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -3750,8 +3365,6 @@ snapshots: ansi-regex@5.0.1: {} - ansi-regex@6.3.0: {} - ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 @@ -3793,12 +3406,6 @@ snapshots: assert-plus@1.0.0: {} - assertion-error-formatter@3.0.0: - dependencies: - diff: 4.0.4 - pad-right: 0.2.2 - repeat-string: 1.6.1 - assertion-error@2.0.1: {} astral-regex@2.0.0: {} @@ -3883,8 +3490,6 @@ snapshots: buffer-equal-constant-time@1.0.1: {} - buffer-from@1.1.2: {} - buffer@5.7.1: dependencies: base64-js: 1.5.1 @@ -3984,8 +3589,6 @@ snapshots: dependencies: delayed-stream: 1.0.0 - commander@15.0.0: {} - commander@6.2.1: {} common-tags@1.8.2: {} @@ -4103,16 +3706,6 @@ snapshots: optionalDependencies: supports-color: 8.1.1 - debug@4.4.3: - dependencies: - ms: 2.1.3 - - debug@4.4.3(supports-color@11.0.0): - dependencies: - ms: 2.1.3 - optionalDependencies: - supports-color: 11.0.0 - debug@4.4.3(supports-color@8.1.1): dependencies: ms: 2.1.3 @@ -4138,8 +3731,6 @@ snapshots: asap: 2.0.6 wrappy: 1.0.2 - diff@4.0.4: {} - diff@5.2.2: {} dotenv@16.6.1: {} @@ -4178,10 +3769,6 @@ snapshots: ansi-colors: 4.1.3 strip-ansi: 6.0.1 - error-stack-parser@2.1.4: - dependencies: - stackframe: 1.3.4 - es-define-property@1.0.1: {} es-errors@1.3.0: {} @@ -4362,10 +3949,6 @@ snapshots: dependencies: escape-string-regexp: 1.0.5 - figures@6.1.0: - dependencies: - is-unicode-supported: 2.1.0 - fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -4382,8 +3965,6 @@ snapshots: transitivePeerDependencies: - supports-color - find-up-simple@1.0.1: {} - find-up@5.0.0: dependencies: locate-path: 6.0.0 @@ -4393,7 +3974,7 @@ snapshots: follow-redirects@1.16.0(debug@4.4.3): optionalDependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) forever-agent@0.6.1: {} @@ -4504,10 +4085,6 @@ snapshots: minimatch: 5.1.9 once: 1.4.0 - global-directory@4.0.1: - dependencies: - ini: 4.1.1 - global-dirs@3.0.1: dependencies: ini: 2.0.0 @@ -4516,10 +4093,6 @@ snapshots: graceful-fs@4.2.11: {} - has-ansi@6.0.2: - dependencies: - ansi-regex: 6.3.0 - has-flag@4.0.0: {} has-symbols@1.1.0: {} @@ -4536,10 +4109,6 @@ snapshots: he@1.2.0: {} - hosted-git-info@9.0.3: - dependencies: - lru-cache: 11.5.2 - html-parse-stringify@4.0.1: {} http-errors@2.0.1: @@ -4559,7 +4128,7 @@ snapshots: https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -4581,10 +4150,6 @@ snapshots: indent-string@4.0.0: {} - indent-string@5.0.0: {} - - index-to-position@1.2.0: {} - inflight@1.0.6: dependencies: once: 1.4.0 @@ -4594,8 +4159,6 @@ snapshots: ini@2.0.0: {} - ini@4.1.1: {} - ipaddr.js@1.9.1: {} is-binary-path@2.1.0: @@ -4615,17 +4178,10 @@ snapshots: global-dirs: 3.0.1 is-path-inside: 3.0.3 - is-installed-globally@1.0.0: - dependencies: - global-directory: 4.0.1 - is-path-inside: 4.0.0 - is-number@7.0.0: {} is-path-inside@3.0.3: {} - is-path-inside@4.0.0: {} - is-plain-obj@2.1.0: {} is-stream@2.0.1: {} @@ -4634,8 +4190,6 @@ snapshots: is-unicode-supported@0.1.0: {} - is-unicode-supported@2.1.0: {} - isexe@2.0.0: {} isstream@0.1.2: {} @@ -4703,10 +4257,6 @@ snapshots: jwa: 2.0.1 safe-buffer: 5.2.1 - knuth-shuffle-seeded@1.0.6: - dependencies: - seed-random: 2.2.0 - lazy-ass@1.6.0: {} listr2@3.14.0(enquirer@2.4.1): @@ -4738,14 +4288,8 @@ snapshots: lodash.isstring@4.0.1: {} - lodash.merge@4.6.2: {} - - lodash.mergewith@4.6.2: {} - lodash.once@4.1.1: {} - lodash.sortby@4.7.0: {} - lodash@4.18.1: {} log-symbols@4.1.0: @@ -4766,8 +4310,6 @@ snapshots: loupe@3.2.1: {} - lru-cache@11.5.2: {} - lru-cache@5.1.1: dependencies: yallist: 3.1.1 @@ -4804,8 +4346,6 @@ snapshots: mime@2.6.0: {} - mime@4.1.0: {} - mimic-fn@2.1.0: {} minimatch@3.1.5: @@ -4874,12 +4414,6 @@ snapshots: dependencies: abbrev: 1.1.1 - normalize-package-data@8.0.0: - dependencies: - hosted-git-info: 9.0.3 - semver: 7.8.5 - validate-npm-package-license: 3.0.4 - normalize-path@3.0.0: {} npm-run-path@4.0.1: @@ -4923,16 +4457,6 @@ snapshots: dependencies: aggregate-error: 3.1.0 - pad-right@0.2.2: - dependencies: - repeat-string: 1.6.1 - - parse-json@8.3.0: - dependencies: - '@babel/code-frame': 7.29.7 - index-to-position: 1.2.0 - type-fest: 4.41.0 - parseurl@1.3.3: {} path-exists@4.0.0: {} @@ -4978,8 +4502,6 @@ snapshots: process@0.11.10: {} - property-expr@2.0.6: {} - proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 @@ -5057,20 +4579,6 @@ snapshots: dependencies: loose-envify: 1.4.0 - read-package-up@12.0.0: - dependencies: - find-up-simple: 1.0.1 - read-pkg: 10.1.0 - type-fest: 5.8.0 - - read-pkg@10.1.0: - dependencies: - '@types/normalize-package-data': 2.4.4 - normalize-package-data: 8.0.0 - parse-json: 8.3.0 - type-fest: 5.8.0 - unicorn-magic: 0.4.0 - readable-stream@3.6.2: dependencies: inherits: 2.0.4 @@ -5083,14 +4591,6 @@ snapshots: readdirp@5.1.1: {} - regexp-match-indices@1.0.2: - dependencies: - regexp-tree: 0.1.27 - - regexp-tree@0.1.27: {} - - repeat-string@1.6.1: {} - request-progress@3.0.0: dependencies: throttleit: 1.0.1 @@ -5160,8 +4660,6 @@ snapshots: dependencies: loose-envify: 1.4.0 - seed-random@2.2.0: {} - semver@6.3.1: {} semver@7.8.5: {} @@ -5253,27 +4751,6 @@ snapshots: source-map-js@1.2.1: {} - source-map-support@0.5.21: - dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 - - source-map@0.6.1: {} - - spdx-correct@3.2.0: - dependencies: - spdx-expression-parse: 3.0.1 - spdx-license-ids: 3.0.23 - - spdx-exceptions@2.5.0: {} - - spdx-expression-parse@3.0.1: - dependencies: - spdx-exceptions: 2.5.0 - spdx-license-ids: 3.0.23 - - spdx-license-ids@3.0.23: {} - split@0.3.3: dependencies: through: 2.3.8 @@ -5290,14 +4767,12 @@ snapshots: safer-buffer: 2.1.2 tweetnacl: 0.14.5 - stackframe@1.3.4: {} - start-server-and-test@2.1.5: dependencies: arg: 5.0.2 bluebird: 3.7.2 check-more-types: 2.24.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) execa: 5.1.1 lazy-ass: 1.6.0 ps-tree: 1.2.0 @@ -5311,8 +4786,6 @@ snapshots: dependencies: duplexer: 0.1.2 - string-argv@0.3.2: {} - string-width@4.2.3: dependencies: emoji-regex: 8.0.0 @@ -5335,7 +4808,7 @@ snapshots: dependencies: component-emitter: 1.3.1 cookiejar: 2.1.4 - debug: 4.4.3 + debug: 4.4.3(supports-color@8.1.1) fast-safe-stringify: 2.1.1 form-data: 4.0.6 formidable: 3.5.4 @@ -5353,8 +4826,6 @@ snapshots: transitivePeerDependencies: - supports-color - supports-color@11.0.0: {} - supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -5363,8 +4834,6 @@ snapshots: dependencies: has-flag: 4.0.0 - tagged-tag@1.0.0: {} - tar@6.2.1: dependencies: chownr: 2.0.0 @@ -5378,8 +4847,6 @@ snapshots: through@2.3.8: {} - tiny-case@1.0.3: {} - tldts-core@6.1.86: {} tldts@6.1.86: @@ -5394,8 +4861,6 @@ snapshots: toidentifier@1.0.1: {} - toposort@2.0.2: {} - tough-cookie@5.1.2: dependencies: tldts: 6.1.86 @@ -5420,14 +4885,6 @@ snapshots: type-fest@0.21.3: {} - type-fest@2.19.0: {} - - type-fest@4.41.0: {} - - type-fest@5.8.0: - dependencies: - tagged-tag: 1.0.0 - type-is@1.6.18: dependencies: media-typer: 0.3.0 @@ -5437,8 +4894,6 @@ snapshots: undici-types@6.21.0: {} - unicorn-magic@0.4.0: {} - universalify@2.0.1: {} unpipe@1.0.0: {} @@ -5455,19 +4910,12 @@ snapshots: dependencies: react: 18.3.1 - util-arity@1.1.0: {} - util-deprecate@1.0.2: {} utils-merge@1.0.1: {} uuid@8.3.2: {} - validate-npm-package-license@3.0.4: - dependencies: - spdx-correct: 3.2.0 - spdx-expression-parse: 3.0.1 - vary@1.1.2: {} verror@1.10.0: @@ -5528,16 +4976,12 @@ snapshots: wrappy@1.0.2: {} - xmlbuilder@15.1.1: {} - y18n@5.0.8: {} yallist@3.1.1: {} yallist@4.0.0: {} - yaml@2.9.0: {} - yargs-parser@20.2.9: {} yargs-unparser@2.0.0: @@ -5564,11 +5008,4 @@ snapshots: yocto-queue@0.1.0: {} - yup@1.7.1: - dependencies: - property-expr: 2.0.6 - tiny-case: 1.0.3 - toposort: 2.0.2 - type-fest: 2.19.0 - zod@3.25.76: {}