diff --git a/.github/workflows/deploy-prod.yml b/.github/workflows/deploy-prod.yml index 24b005b..45c43e6 100644 --- a/.github/workflows/deploy-prod.yml +++ b/.github/workflows/deploy-prod.yml @@ -31,7 +31,7 @@ jobs: - name: Genereer app token (Release proces app) id: app-token - uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 with: app-id: ${{ secrets.RELEASE_PROCES_APP_ID }} private-key: ${{ secrets.RELEASE_PROCES_APP_PRIVATE_KEY }} @@ -39,7 +39,7 @@ jobs: repositories: ${{ steps.infra-repo.outputs.repo }} - name: Checkout don-infra - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: repository: ${{ env.INFRA_REPO }} token: ${{ steps.app-token.outputs.token }} @@ -54,8 +54,8 @@ jobs: - name: Install yq run: | set -e - sudo wget -O /usr/local/bin/yq https://github.com/mikefarah/yq/releases/download/v4.44.3/yq_linux_amd64 - echo "a2c097180dd884a8d50c956ee16a9cec070f30a7947cf4ebf87d5f36213e9ed7 /usr/local/bin/yq" | sha256sum -c + sudo wget -O /usr/local/bin/yq https://github.com/mikefarah/yq/releases/download/v4.53.2/yq_linux_amd64 + echo "d56bf5c6819e8e696340c312bd70f849dc1678a7cda9c2ad63eebd906371d56b /usr/local/bin/yq" | sha256sum -c sudo chmod +x /usr/local/bin/yq - name: Update image tag in prod overlay @@ -91,4 +91,4 @@ jobs: **Branch:** \`${{ github.ref_name }}\` **Commit:** ${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }} - Merge deze PR om de nieuwe versie naar productie te deployen." \ No newline at end of file + Merge deze PR om de nieuwe versie naar productie te deployen." diff --git a/.github/workflows/deploy-test.yml b/.github/workflows/deploy-test.yml index 6fdc437..5cede02 100644 --- a/.github/workflows/deploy-test.yml +++ b/.github/workflows/deploy-test.yml @@ -48,20 +48,20 @@ jobs: packages: write steps: - name: Checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd + uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 - name: Login to container registry - uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 + uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push image - uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 + uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0 with: context: . push: true @@ -88,7 +88,7 @@ jobs: - name: Genereer app token (Release proces app) id: app-token - uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 with: app-id: ${{ secrets.RELEASE_PROCES_APP_ID }} private-key: ${{ secrets.RELEASE_PROCES_APP_PRIVATE_KEY }} @@ -96,7 +96,7 @@ jobs: repositories: ${{ steps.infra-repo.outputs.repo }} - name: Checkout don-infra - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: repository: ${{ env.INFRA_REPO }} token: ${{ steps.app-token.outputs.token }} @@ -104,8 +104,8 @@ jobs: - name: Install yq run: | set -e - sudo wget -O /usr/local/bin/yq https://github.com/mikefarah/yq/releases/download/v4.44.3/yq_linux_amd64 - echo "a2c097180dd884a8d50c956ee16a9cec070f30a7947cf4ebf87d5f36213e9ed7 /usr/local/bin/yq" | sha256sum -c + sudo wget -O /usr/local/bin/yq https://github.com/mikefarah/yq/releases/download/v4.53.2/yq_linux_amd64 + echo "d56bf5c6819e8e696340c312bd70f849dc1678a7cda9c2ad63eebd906371d56b /usr/local/bin/yq" | sha256sum -c sudo chmod +x /usr/local/bin/yq - name: Update image tag in test overlay @@ -125,4 +125,4 @@ jobs: Branch: ${{ github.ref_name }} Commit: ${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}" - git push \ No newline at end of file + git push diff --git a/.github/workflows/json-ci.yml b/.github/workflows/json-ci.yml index 152574c..2a8b346 100644 --- a/.github/workflows/json-ci.yml +++ b/.github/workflows/json-ci.yml @@ -12,11 +12,11 @@ jobs: issues: write pull-requests: write steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: fetch-depth: 0 - name: Run Super-Linter - uses: super-linter/super-linter@v8.6.0 + uses: super-linter/super-linter@9e863354e3ff62e0727d37183162c4a88873df41 # v8.6.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} VALIDATE_ALL_CODEBASE: true diff --git a/.github/workflows/node-ci.yml b/.github/workflows/node-ci.yml index 00d9839..87454a1 100644 --- a/.github/workflows/node-ci.yml +++ b/.github/workflows/node-ci.yml @@ -9,12 +9,12 @@ jobs: name: Lint runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Setup Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: - node-version: 20 + node-version: 22 cache: npm - name: Install dependencies @@ -30,17 +30,17 @@ jobs: permissions: packages: write steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Login to GitHub Container Registry - uses: docker/login-action@v4 + uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build & Push Docker image - uses: docker/build-push-action@v7 + uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0 with: context: . push: true diff --git a/Dockerfile b/Dockerfile index 0d56ab1..a74306c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,14 +1,24 @@ -FROM node:lts-alpine AS runtime - +FROM node:22-alpine AS build WORKDIR /app - -# Install dependencies COPY package.json package-lock.json ./ RUN npm ci +COPY tsconfig.json ./ +COPY api ./api +COPY controllers ./controllers +COPY decorators ./decorators +COPY models ./models +COPY implementation ./implementation +COPY app ./app +RUN npm run build -# Copy source -COPY . . +FROM node:22-alpine AS runtime +WORKDIR /app +ENV NODE_ENV=production +COPY package.json package-lock.json ./ +RUN npm ci --omit=dev +COPY --from=build /app/dist ./dist +COPY api ./api -EXPOSE 8080 +EXPOSE 1338 -CMD ["node", "index.js"] +CMD ["node", "dist/app/index.js"] diff --git a/README 2.md b/README 2.md deleted file mode 100644 index 1db34a2..0000000 --- a/README 2.md +++ /dev/null @@ -1,104 +0,0 @@ - -# OpenAPI Generated JavaScript/Express Server - -## Overview -This server was generated using the [OpenAPI Generator](https://openapi-generator.tech) project. The code generator, and it's generated code allows you to develop your system with an API-First attitude, where the API contract is the anchor and definer of your project, and your code and business-logic aims to complete and comply to the terms in the API contract. - -### prerequisites -- NodeJS >= 10.6 -- NPM >= 6.10.0 - -The code was written on a mac, so assuming all should work smoothly on Linux-based computers. However, there is no reason not to run this library on Windows-based machines. If you find an OS-related problem, please open an issue and it will be resolved. - -### Running the server -#### This is a long read, but there's a lot to understand. Please take the time to go through this. -1. Use the OpenAPI Generator to generate your application: -Assuming you have Java (1.8+), and [have the jar](https://github.com/openapitools/openapi-generator#13---download-jar) to generate the application, run: -```java -jar {path_to_jar_file} generate -g nodejs-express-server -i {openapi yaml/json file} -o {target_directory_where_the_app_will_be_installed} ``` -If you do not have the jar, or do not want to run Java from your local machine, follow instructions on the [OpenAPITools page](https://github.com/openapitools/openapi-generator). You can run the script online, on docker, and various other ways. -2. Go to the generated directory you defined. There's a fully working NodeJS-ExpressJs server waiting for you. This is important - the code is yours to change and update! Look at config.js and see that the settings there are ok with you - the server will run on port 8080, and files will be uploaded to a new directory 'uploaded_files'. -3. The server will base itself on an openapi.yaml file which is located under /api/openapi.yaml. This is not exactly the same file that you used to generate the app: -I. If you have `application/json` contentBody that was defined inside the path object - the generate will have moved it to the components/schemas section of the openapi document. -II. Every process has a new element added to it - `x-eov-operation-handler: controllers/PetController` which directs the call to that file. -III. We have a Java application that translates the operationId to a method, and a nodeJS script that does the same process to call that method. Both are converting the method to `camelCase`, but might have discrepancy. Please pay attention to the operationID names, and see that they are represented in the `controllers` and `services` directories. -4. Take the time to understand the structure of the application. There might be bugs, and there might be settings and business-logic that does not meet your expectation. Instead of dumping this solution and looking for something else - see if you can make the generated code work for you. -To keep the explanation short (a more detailed explanation will follow): Application starts with a call to index.js (this is where you will plug in the db later). It calls expressServer.js which is where the express.js and openapi-validator kick in. This is an important file. Learn it. All calls to endpoints that were configured in the openapi.yaml document go to `controllers/{name_of_tag_which_the_operation_was_associated_with}.js`, which is a very small method. All the business-logic lies in `controllers/Controller.js`, and from there - to `services/{name_of_tag_which_the_operation_was_associated_with}.js`. - -5. Once you've understood what is *going* to happen, launch the app and ensure everything is working as expected: -``` -npm start -``` -### Tests -Unfortunately, I have not written any unit-tests. Those will come in the future. However, the package does come with all that is needed to write and run tests - mocha and sinon and the related libraries are included in the package.js and will be installed upon npm install command - -### Mocking responses -- Enable the mock layer with `npm run start-mock` (wraps `USE_MOCKS=true` for you). Setting `USE_MOCKS` or `MOCKS_ENABLED` to `true/1/yes/on` achieves the same effect for custom scripts. -- Without any custom mock files the server auto-generates example payloads from the OpenAPI document (using response examples/schema defaults). -- Add overrides in `mocks/.js` when you need to control a specific operation. Export functions with the same operationIds. -- A handler can return a plain payload (automatically wrapped as a success), the result of `Service.successResponse(...)` to customize status codes, or `Service.rejectResponse(...)`/throw an error to simulate failures. - -```javascript -const Service = require('../services/Service'); - -module.exports = { - listPets: async () => Service.successResponse([{ id: 1, name: 'Fluffy' }]), -}; -``` - -### View and test the API -(Assuming no changes were made to config.js) - -1. API documentation, and to check the available endpoints: -http://localhost:8080/api-docs/. To -2. Download the openapi.yaml document: http://localhost:8080/openapi. -3. Every call to an endpoint that was defined in the openapi document will return a 200 and a list of all the parameters and objects that were sent in the request. -4. Endpoints that require security need to have security handlers configured before they can return a successful response. At this point they will return [ a response code of 401](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/401). -5. ##### At this stage the server does not support document body sent in xml format. - -### Node version and guidelines -The code was written using Node version 10.6, and complies to the [Airbnb .eslint guiding rules](https://github.com/airbnb/javascript). - -### Project Files -#### Root Directory: -In the root directory we have (besides package.json, config.js, and log files): -- **logger.js** - where we define the logger for the project. The project uses winston, but the purpose of this file is to enable users to change and modify their own logger behavior. -- **index.js** - This is the project's 'main' file, and from here we launch the application. This is a very short and concise file, and the idea behind launching from this short file is to allow use-cases of launching the server with different parameters (changing config and/or logger) without affecting the rest of the code. -- **expressServer.js** - The core of the Express.js server. This is where the express server is initialized, together with the OpenAPI validator, OpenAPI UI, and other libraries needed to start our server. If we want to add external links, that's where they would go. Our project uses the [express-openapi-validator](https://www.npmjs.com/package/express-openapi-validator) library that acts as a first step in the routing process - requests that are directed to paths defined in the `openapi.yaml` file are caught by this process, and it's parameters and bodyContent are validated against the schema. A successful result of this validation will be a new 'openapi' object added to the request. If the path requested is not part of the openapi.yaml file, the validator ignores the request and passes it on, as is, down the flow of the Express server. - -#### api/ -- **openapi.yaml** - This is the OpenAPI contract to which this server will comply. The file was generated using the codegen, and should contain everything needed to run the API Gateway - no references to external models/schemas. - -#### utils/ -Currently a single file: - -- **openapiRouter.js** - This is where the routing to our back-end code happens. If the request object includes an ```openapi``` object, it picks up the following values (that are part of the ```openapi.yaml``` file): 'x-openapi-router-controller', and 'x-openapi-router-service'. These variables are names of files/classes in the controllers and services directories respectively. The operationId of the request is also extracted. The operationId is a method in the controller and the service that was generated as part of the codegen process. The routing process sends the request and response objects to the controller, which will extract the expected variables from the request, and send it to be processed by the service, returning the response from the service to the caller. - -#### controllers/ -After validating the request, and ensuring this belongs to our API gateway, we send the request to a `controller`, where the variables and parameters are extracted from the request and sent to the relevant `service` for processing. The `controller` handles the response from the `service` and builds the appropriate HTTP response to be sent back to the user. - -- **index.js** - load all the controllers that were generated for this project, and export them to be used dynamically by the `openapiRouter.js`. If you would like to customize your controller, it is advised that you link to your controller here, and ensure that the codegen does not rewrite this file. - -- **Controller.js** - The core processor of the generated controllers. The generated controllers are designed to be as slim and generic as possible, referencing to the `Controller.js` for the business logic of parsing the needed variables and arguments from the request, and for building the HTTP response which will be sent back. The `Controller.js` is a class with static methods. - -- **.js** - auto-generated code, processing all the operations. The Controller is a class that is constructed with the service class it will be sending the request to. Every request defined by the `openapi.yaml` has an operationId. The operationId is the name of the method that will be called. Every method receives the request and response, and calls the `Controller.js` to process the request and response, adding the service method that should be called for the actual business-logic processing. - -#### services/ -This is where the API Gateway ends, and the unique business-logic of your application kicks in. Every endpoint in the `openapi.yaml` has a variable 'x-openapi-router-service', which is the name of the service class that is generated. The operationID of the endpoint is the name of the method that will be called. The generated code provides a simple promise with a try/catch clause. A successful operation ends with a call to the generic `Service.js` to build a successful response (payload and response code), and a failure will call the generic `Service.js` to build a response with an error object and the relevant response code. It is recommended to have the services be generated automatically once, and after the initial build add methods manually. - -- **index.js** - load all the services that were generated for this project, and export them to be used dynamically by the `openapiRouter.js`. If you would like to customize your service, it is advised that you link to your controller here, and ensure that the codegen does not rewrite this file. - -- **Service.js** - A utility class, very simple and thin at this point, with two static methods for building a response object for successful and failed results in the service operation. The default response code is 200 for success and 500 for failure. It is recommended to send more accurate response codes and override these defaults when relevant. - -- **.js** - auto-generated code, providing a stub Promise for each operationId defined in the `openapi.yaml`. Each method receives the variables that were defined in the `openapi.yaml` file, and wraps a Promise in a try/catch clause. The Promise resolves both success and failure in a call to the `Service.js` utility class for building the appropriate response that will be sent back to the Controller and then to the caller of this endpoint. - -#### tests/ -- **serverTests.js** - basic server validation tests, checking that the server is up, that a call to an endpoint within the scope of the `openapi.yaml` file returns 200, that a call to a path outside that scope returns 200 if it exists and a 404 if not. -- **routingTests.js** - Runs through all the endpoints defined in the `openapi.yaml`, and constructs a dummy request to send to the server. Confirms that the response code is 200. At this point requests containing xml or formData fail - currently they are not supported in the router. -- **additionalEndpointsTests.js** - A test file for all the endpoints that are defined outside the openapi.yaml scope. Confirms that these endpoints return a successful 200 response. - - -Future tests should be written to ensure that the response of every request sent should conform to the structure defined in the `openapi.yaml`. This test will fail 100% initially, and the job of the development team will be to clear these tests. - - -#### models/ -Currently a concept awaiting feedback. The idea is to have the objects defined in the openapi.yaml act as models which are passed between the different modules. This will conform the programmers to interact using defined objects, rather than loosely-defined JSON objects. Given the nature of JavaScript programmers, who want to work with their own bootstrapped parameters, this concept might not work. Keeping this here for future discussion and feedback. diff --git a/README.md b/README.md index 1db34a2..d9a044f 100644 --- a/README.md +++ b/README.md @@ -1,104 +1,127 @@ +# DON Tools API v1 -# OpenAPI Generated JavaScript/Express Server +HTTP API voor de tools op `developer.overheid.nl`. -## Overview -This server was generated using the [OpenAPI Generator](https://openapi-generator.tech) project. The code generator, and it's generated code allows you to develop your system with an API-First attitude, where the API contract is the anchor and definer of your project, and your code and business-logic aims to complete and comply to the terms in the API contract. +Deze repository bevat de API-laag voor versie 1 van de Tools API: routing, OpenAPI-validatie, +response headers, foutafhandeling en de koppeling naar de daadwerkelijke businesslogica. Die +businesslogica staat in `@developer-overheid-nl/don-tools-logic` en wordt los beheerd in +`don-tools-api-v2`. -### prerequisites -- NodeJS >= 10.6 -- NPM >= 6.10.0 +## Wat zit hierin? -The code was written on a mac, so assuming all should work smoothly on Linux-based computers. However, there is no reason not to run this library on Windows-based machines. If you find an OS-related problem, please open an issue and it will be resolved. +- NestJS met Fastify als HTTP runtime +- OpenAPI request- en responsevalidatie via `openapi-backend` +- Gegenereerde controller- en modelbestanden op basis van `api/openapi.yaml` +- Implementatie-adapter in `implementation/tools-api.service.ts` +- Docker image voor deployment op poort `1338` -### Running the server -#### This is a long read, but there's a lot to understand. Please take the time to go through this. -1. Use the OpenAPI Generator to generate your application: -Assuming you have Java (1.8+), and [have the jar](https://github.com/openapitools/openapi-generator#13---download-jar) to generate the application, run: -```java -jar {path_to_jar_file} generate -g nodejs-express-server -i {openapi yaml/json file} -o {target_directory_where_the_app_will_be_installed} ``` -If you do not have the jar, or do not want to run Java from your local machine, follow instructions on the [OpenAPITools page](https://github.com/openapitools/openapi-generator). You can run the script online, on docker, and various other ways. -2. Go to the generated directory you defined. There's a fully working NodeJS-ExpressJs server waiting for you. This is important - the code is yours to change and update! Look at config.js and see that the settings there are ok with you - the server will run on port 8080, and files will be uploaded to a new directory 'uploaded_files'. -3. The server will base itself on an openapi.yaml file which is located under /api/openapi.yaml. This is not exactly the same file that you used to generate the app: -I. If you have `application/json` contentBody that was defined inside the path object - the generate will have moved it to the components/schemas section of the openapi document. -II. Every process has a new element added to it - `x-eov-operation-handler: controllers/PetController` which directs the call to that file. -III. We have a Java application that translates the operationId to a method, and a nodeJS script that does the same process to call that method. Both are converting the method to `camelCase`, but might have discrepancy. Please pay attention to the operationID names, and see that they are represented in the `controllers` and `services` directories. -4. Take the time to understand the structure of the application. There might be bugs, and there might be settings and business-logic that does not meet your expectation. Instead of dumping this solution and looking for something else - see if you can make the generated code work for you. -To keep the explanation short (a more detailed explanation will follow): Application starts with a call to index.js (this is where you will plug in the db later). It calls expressServer.js which is where the express.js and openapi-validator kick in. This is an important file. Learn it. All calls to endpoints that were configured in the openapi.yaml document go to `controllers/{name_of_tag_which_the_operation_was_associated_with}.js`, which is a very small method. All the business-logic lies in `controllers/Controller.js`, and from there - to `services/{name_of_tag_which_the_operation_was_associated_with}.js`. +## Endpoints -5. Once you've understood what is *going* to happen, launch the app and ensure everything is working as expected: -``` -npm start +De OpenAPI-specificatie staat in `api/openapi.yaml` en `api/openapi.json`. + +Bij runtime worden deze ook beschikbaar gemaakt op: + +- `GET /openapi.yaml` +- `GET /openapi.json` + +Belangrijkste tools-endpoints: + +- `POST /v1/oas/validate` +- `POST /v1/oas/convert` +- `POST /v1/oas/bundle` +- `POST /v1/oas/generate` +- `POST /v1/oas/postman` +- `POST /v1/arazzo/markdown` +- `POST /v1/arazzo/mermaid` +- `POST /v1/auth/clients` + +## Lokaal ontwikkelen + +Vereisten: + +- Node.js 22+ +- npm + +Installeren en starten: + +```sh +npm install +npm run dev ``` -### Tests -Unfortunately, I have not written any unit-tests. Those will come in the future. However, the package does come with all that is needed to write and run tests - mocha and sinon and the related libraries are included in the package.js and will be installed upon npm install command -### Mocking responses -- Enable the mock layer with `npm run start-mock` (wraps `USE_MOCKS=true` for you). Setting `USE_MOCKS` or `MOCKS_ENABLED` to `true/1/yes/on` achieves the same effect for custom scripts. -- Without any custom mock files the server auto-generates example payloads from the OpenAPI document (using response examples/schema defaults). -- Add overrides in `mocks/.js` when you need to control a specific operation. Export functions with the same operationIds. -- A handler can return a plain payload (automatically wrapped as a success), the result of `Service.successResponse(...)` to customize status codes, or `Service.rejectResponse(...)`/throw an error to simulate failures. +De API luistert standaard op `http://localhost:1338`. -```javascript -const Service = require('../services/Service'); +Handige scripts: -module.exports = { - listPets: async () => Service.successResponse([{ id: 1, name: 'Fluffy' }]), -}; +```sh +npm run build # TypeScript build naar dist/ +npm start # start de gebouwde app +npm test # Vitest tests +npm run lint # Biome lint +npm run typecheck # TypeScript typecheck zonder output ``` -### View and test the API -(Assuming no changes were made to config.js) +## Omgevingsvariabelen -1. API documentation, and to check the available endpoints: -http://localhost:8080/api-docs/. To -2. Download the openapi.yaml document: http://localhost:8080/openapi. -3. Every call to an endpoint that was defined in the openapi document will return a 200 and a list of all the parameters and objects that were sent in the request. -4. Endpoints that require security need to have security handlers configured before they can return a successful response. At this point they will return [ a response code of 401](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/401). -5. ##### At this stage the server does not support document body sent in xml format. +- `PORT`: poort waarop de API luistert, standaard `1338` +- `HOST`: host waarop Fastify bindt, standaard `0.0.0.0` +- `OPENAPI_MOCK`: zet mock responses aan met `true`, `1`, `yes` of `on` -### Node version and guidelines -The code was written using Node version 10.6, and complies to the [Airbnb .eslint guiding rules](https://github.com/airbnb/javascript). +Mock mode kan ook direct via: -### Project Files -#### Root Directory: -In the root directory we have (besides package.json, config.js, and log files): -- **logger.js** - where we define the logger for the project. The project uses winston, but the purpose of this file is to enable users to change and modify their own logger behavior. -- **index.js** - This is the project's 'main' file, and from here we launch the application. This is a very short and concise file, and the idea behind launching from this short file is to allow use-cases of launching the server with different parameters (changing config and/or logger) without affecting the rest of the code. -- **expressServer.js** - The core of the Express.js server. This is where the express server is initialized, together with the OpenAPI validator, OpenAPI UI, and other libraries needed to start our server. If we want to add external links, that's where they would go. Our project uses the [express-openapi-validator](https://www.npmjs.com/package/express-openapi-validator) library that acts as a first step in the routing process - requests that are directed to paths defined in the `openapi.yaml` file are caught by this process, and it's parameters and bodyContent are validated against the schema. A successful result of this validation will be a new 'openapi' object added to the request. If the path requested is not part of the openapi.yaml file, the validator ignores the request and passes it on, as is, down the flow of the Express server. +```sh +npm run dev-mock +``` -#### api/ -- **openapi.yaml** - This is the OpenAPI contract to which this server will comply. The file was generated using the codegen, and should contain everything needed to run the API Gateway - no references to external models/schemas. +## Relatie met `don-tools-api-v2` -#### utils/ -Currently a single file: +`don-tools-api` is de v1 HTTP-adapter. De herbruikbare logica zit in +`@developer-overheid-nl/don-tools-logic`. -- **openapiRouter.js** - This is where the routing to our back-end code happens. If the request object includes an ```openapi``` object, it picks up the following values (that are part of the ```openapi.yaml``` file): 'x-openapi-router-controller', and 'x-openapi-router-service'. These variables are names of files/classes in the controllers and services directories respectively. The operationId of the request is also extracted. The operationId is a method in the controller and the service that was generated as part of the codegen process. The routing process sends the request and response objects to the controller, which will extract the expected variables from the request, and send it to be processed by the service, returning the response from the service to the caller. +Zodra de logic package op npm gepubliceerd is, pin deze API op een expliciete packageversie: -#### controllers/ -After validating the request, and ensuring this belongs to our API gateway, we send the request to a `controller`, where the variables and parameters are extracted from the request and sent to the relevant `service` for processing. The `controller` handles the response from the `service` and builds the appropriate HTTP response to be sent back to the user. +```sh +npm install @developer-overheid-nl/don-tools-logic@ +``` -- **index.js** - load all the controllers that were generated for this project, and export them to be used dynamically by the `openapiRouter.js`. If you would like to customize your controller, it is advised that you link to your controller here, and ensure that the codegen does not rewrite this file. +Gebruik liever een npm-versie dan een GitHub dependency in CI/CD. Dat voorkomt dat builds afhankelijk +worden van GitHub SSH keys of repository tokens. -- **Controller.js** - The core processor of the generated controllers. The generated controllers are designed to be as slim and generic as possible, referencing to the `Controller.js` for the business logic of parsing the needed variables and arguments from the request, and for building the HTTP response which will be sent back. The `Controller.js` is a class with static methods. +## Docker -- **.js** - auto-generated code, processing all the operations. The Controller is a class that is constructed with the service class it will be sending the request to. Every request defined by the `openapi.yaml` has an operationId. The operationId is the name of the method that will be called. Every method receives the request and response, and calls the `Controller.js` to process the request and response, adding the service method that should be called for the actual business-logic processing. +Build lokaal: -#### services/ -This is where the API Gateway ends, and the unique business-logic of your application kicks in. Every endpoint in the `openapi.yaml` has a variable 'x-openapi-router-service', which is the name of the service class that is generated. The operationID of the endpoint is the name of the method that will be called. The generated code provides a simple promise with a try/catch clause. A successful operation ends with a call to the generic `Service.js` to build a successful response (payload and response code), and a failure will call the generic `Service.js` to build a response with an error object and the relevant response code. It is recommended to have the services be generated automatically once, and after the initial build add methods manually. +```sh +docker build -t don-tools-api . +``` -- **index.js** - load all the services that were generated for this project, and export them to be used dynamically by the `openapiRouter.js`. If you would like to customize your service, it is advised that you link to your controller here, and ensure that the codegen does not rewrite this file. +Run lokaal: -- **Service.js** - A utility class, very simple and thin at this point, with two static methods for building a response object for successful and failed results in the service operation. The default response code is 200 for success and 500 for failure. It is recommended to send more accurate response codes and override these defaults when relevant. +```sh +docker run --rm -p 1338:1338 don-tools-api +``` -- **.js** - auto-generated code, providing a stub Promise for each operationId defined in the `openapi.yaml`. Each method receives the variables that were defined in the `openapi.yaml` file, and wraps a Promise in a try/catch clause. The Promise resolves both success and failure in a call to the `Service.js` utility class for building the appropriate response that will be sent back to the Controller and then to the caller of this endpoint. +## Checks voor een wijziging -#### tests/ -- **serverTests.js** - basic server validation tests, checking that the server is up, that a call to an endpoint within the scope of the `openapi.yaml` file returns 200, that a call to a path outside that scope returns 200 if it exists and a 404 if not. -- **routingTests.js** - Runs through all the endpoints defined in the `openapi.yaml`, and constructs a dummy request to send to the server. Confirms that the response code is 200. At this point requests containing xml or formData fail - currently they are not supported in the router. -- **additionalEndpointsTests.js** - A test file for all the endpoints that are defined outside the openapi.yaml scope. Confirms that these endpoints return a successful 200 response. +Draai minimaal: +```sh +npm run lint +npm run build +npm test +``` -Future tests should be written to ensure that the response of every request sent should conform to the structure defined in the `openapi.yaml`. This test will fail 100% initially, and the job of the development team will be to clear these tests. +Bij wijzigingen aan `api/openapi.yaml` of gegenereerde bestanden: controleer ook of +`api/openapi.json`, `controllers/`, `models/` en `api/` nog overeenkomen met het contract. +## Repository-indeling -#### models/ -Currently a concept awaiting feedback. The idea is to have the objects defined in the openapi.yaml act as models which are passed between the different modules. This will conform the programmers to interact using defined objects, rather than loosely-defined JSON objects. Given the nature of JavaScript programmers, who want to work with their own bootstrapped parameters, this concept might not work. Keeping this here for future discussion and feedback. +```text +api/ OpenAPI contract en gegenereerde API interfaces +app/ NestJS/Fastify bootstrap en OpenAPI middleware +controllers/ Gegenereerde NestJS controllers +decorators/ Gegenereerde request decorators +implementation/ Handgeschreven adapter naar don-tools-logic +models/ Gegenereerde request/response modellen +test/ Vitest tests +``` diff --git a/api/ToolsApi.ts b/api/ToolsApi.ts new file mode 100644 index 0000000..34e23db --- /dev/null +++ b/api/ToolsApi.ts @@ -0,0 +1,33 @@ +import { Injectable } from '@nestjs/common'; +import type { FastifyReply } from 'fastify'; +import { Observable } from 'rxjs'; +import { ModelsKeycloakClientResult, ModelsLintResult, OasInput, UntrustClientInput, } from '../models'; + + +@Injectable() +export abstract class ToolsApi { + + abstract arazzoMarkdown(oasInput: OasInput | undefined, request: Request, reply: FastifyReply): string | Promise | Observable; + + + abstract arazzoMermaid(oasInput: OasInput | undefined, request: Request, reply: FastifyReply): string | Promise | Observable; + + + abstract bundleOAS(oasInput: OasInput | undefined, request: Request, reply: FastifyReply): void | Promise | Observable; + + + abstract convertOAS(oasInput: OasInput | undefined, request: Request, reply: FastifyReply): void | Promise | Observable; + + + abstract createPostmanCollection(oasInput: OasInput | undefined, request: Request, reply: FastifyReply): void | Promise | Observable; + + + abstract generateOAS(oasInput: OasInput | undefined, request: Request, reply: FastifyReply): object | Promise | Observable; + + + abstract untrustClient(untrustClientInput: UntrustClientInput | undefined, request: Request, reply: FastifyReply): ModelsKeycloakClientResult | Promise | Observable; + + + abstract validatorOpenAPIPost(oasInput: OasInput | undefined, request: Request, reply: FastifyReply): ModelsLintResult | Promise | Observable; + +} diff --git a/api/index.ts b/api/index.ts new file mode 100644 index 0000000..b832067 --- /dev/null +++ b/api/index.ts @@ -0,0 +1 @@ +export * from './ToolsApi'; diff --git a/api/openapi.json b/api/openapi.json index 02ca14c..0f2e2f7 100644 --- a/api/openapi.json +++ b/api/openapi.json @@ -17,7 +17,7 @@ }, { "description": "Test", - "url": "https://api.don.projects.digilab.network/tools/v1" + "url": "https://api.don.apps.digilab.network/tools/v1" } ], "tags": [ @@ -187,7 +187,7 @@ "/v1/oas/convert": { "post": { "description": "Converteert OpenAPI naar de laatst ondersteunde versie (standaard 3.1). Meegegeven targetVersion (3.0 of 3.1) bepaalt het doel. Body: { oasUrl } of { oasBody } (stringified JSON of YAML).", - "operationId": "ConvertOAS", + "operationId": "convertOAS", "requestBody": { "content": { "application/json": { @@ -225,7 +225,8 @@ "tags": [ "Tools" ], - "x-eov-operation-handler": "controllers/ToolsController" + "x-eov-operation-handler": "controllers/ToolsController", + "x-original-operationId": "ConvertOAS" } }, "/v1/oas/bundle": { @@ -275,7 +276,7 @@ "/v1/oas/generate": { "post": { "description": "Genereert een boilerplate OpenAPI specificatie op basis van JSON-invoer. Body: { oasUrl } of { oasBody } (stringified JSON).", - "operationId": "GenerateOAS", + "operationId": "generateOAS", "requestBody": { "content": { "application/json": { @@ -320,7 +321,8 @@ "tags": [ "Tools" ], - "x-eov-operation-handler": "controllers/ToolsController" + "x-eov-operation-handler": "controllers/ToolsController", + "x-original-operationId": "GenerateOAS" } }, "/v1/oas/validate": { @@ -377,7 +379,7 @@ "/v1/oas/postman": { "post": { "description": "Converteert OpenAPI naar Postman Collection JSON. Body: { oasUrl } of { oasBody } (stringified JSON of YAML).", - "operationId": "CreatePostmanCollection", + "operationId": "createPostmanCollection", "requestBody": { "content": { "application/json": { @@ -415,7 +417,8 @@ "tags": [ "Tools" ], - "x-eov-operation-handler": "controllers/ToolsController" + "x-eov-operation-handler": "controllers/ToolsController", + "x-original-operationId": "CreatePostmanCollection" } } }, diff --git a/api/openapi.yaml b/api/openapi.yaml new file mode 100644 index 0000000..0f2e2f7 --- /dev/null +++ b/api/openapi.yaml @@ -0,0 +1,665 @@ +{ + "openapi": "3.0.1", + "info": { + "contact": { + "email": "developer.overheid@geonovum.nl", + "name": "Team developer.overheid.nl", + "url": "https://github.com/developer-overheid-nl/don-tools-api/issues" + }, + "description": "API to access the tools endpoints of developer.overheid.nl.\n\n## Auth\n\nThis API provides tools endpoints that can be accessed with either an API key or a client credentials token.\n\n### API key\n\nUsing an API key, you can access the tools endpoints.\nThese requests can also be made from the browser.\nRequest a read-only API key at https://apis.developer.overheid.nl/apis/key-aanvragen.\nSimply pass the obtained API key with each request using the `X-Api-Key` header.\n\n### Client credentials token\n\nUsing a client credentials token, you can access the tools endpoints.\nTo obtain the token, perform a `POST` request to `https://auth.developer.overheid.nl/realms/don/protocol/openid-connect/token` with the following Form URL Encoded body:\n- `grant_type`: `client_credentials`\n- `scope`: `tools`\n- `client_id`: the client id you received from us\n- `client_secret`: the client secret you received from us\n\nPass the obtained token with each request using the `Authorization` header. Example:\n\n`Authorization`: `Bearer {ACCESS_TOKEN}` (replace `{ACCESS_TOKEN}` with the obtained `access_token`)", + "title": "Tools API v1", + "version": "1.0.0" + }, + "servers": [ + { + "description": "Production", + "url": "https://api.developer.overheid.nl/tools/v1" + }, + { + "description": "Test", + "url": "https://api.don.apps.digilab.network/tools/v1" + } + ], + "tags": [ + { + "description": "Tools API V1 routes", + "name": "API v1" + }, + { + "description": "Conversies en hulpmiddelen", + "name": "Tools" + } + ], + "paths": { + "/v1/arazzo/markdown": { + "post": { + "description": "Genereert alleen de Markdown-uitvoer van een Arazzo specificatie. Body: { oasUrl|oasBody }", + "operationId": "arazzoMarkdown", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OasInput" + } + } + } + }, + "responses": { + "200": { + "content": { + "text/markdown": { + "schema": { + "type": "string" + } + } + }, + "description": "OK", + "headers": { + "API-Version": { + "description": "De API-versie van de response", + "explode": false, + "schema": { + "type": "string" + }, + "style": "simple" + } + } + }, + "404": { + "$ref": "#/components/responses/404" + } + }, + "security": [ + { + "apiKey": [], + "clientCredentials": [] + } + ], + "summary": "Arazzo Markdown (POST)", + "tags": [ + "Tools" + ], + "x-eov-operation-handler": "controllers/ToolsController" + } + }, + "/v1/arazzo/mermaid": { + "post": { + "description": "Genereert alleen de Mermaid flowchart van een Arazzo specificatie. Body: { oasUrl|oasBody }", + "operationId": "arazzoMermaid", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OasInput" + } + } + } + }, + "responses": { + "200": { + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + }, + "description": "OK", + "headers": { + "API-Version": { + "description": "De API-versie van de response", + "explode": false, + "schema": { + "type": "string" + }, + "style": "simple" + } + } + }, + "404": { + "$ref": "#/components/responses/404" + } + }, + "security": [ + { + "apiKey": [], + "clientCredentials": [] + } + ], + "summary": "Arazzo Mermaid (POST)", + "tags": [ + "Tools" + ], + "x-eov-operation-handler": "controllers/ToolsController" + } + }, + "/v1/auth/clients": { + "post": { + "description": "Maak een client aan via de admin API. Body bevat Email.", + "operationId": "untrustClient", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UntrustClientInput" + } + } + } + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsKeycloakClientResult" + } + } + }, + "description": "OK", + "headers": { + "API-Version": { + "description": "De API-versie van de response", + "explode": false, + "schema": { + "type": "string" + }, + "style": "simple" + } + } + }, + "404": { + "$ref": "#/components/responses/404" + } + }, + "security": [ + { + "apiKey": [], + "clientCredentials": [] + } + ], + "summary": "Maak client (POST)", + "tags": [ + "Tools" + ], + "x-eov-operation-handler": "controllers/ToolsController" + } + }, + "/v1/oas/convert": { + "post": { + "description": "Converteert OpenAPI naar de laatst ondersteunde versie (standaard 3.1). Meegegeven targetVersion (3.0 of 3.1) bepaalt het doel. Body: { oasUrl } of { oasBody } (stringified JSON of YAML).", + "operationId": "convertOAS", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OasInput" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "headers": { + "API-Version": { + "description": "De API-versie van de response", + "explode": false, + "schema": { + "type": "string" + }, + "style": "simple" + } + } + }, + "404": { + "$ref": "#/components/responses/404" + } + }, + "security": [ + { + "apiKey": [], + "clientCredentials": [] + } + ], + "summary": "Converteer OpenAPI 3.0/3.1", + "tags": [ + "Tools" + ], + "x-eov-operation-handler": "controllers/ToolsController", + "x-original-operationId": "ConvertOAS" + } + }, + "/v1/oas/bundle": { + "post": { + "description": "Bundelt een OpenAPI specificatie en lost externe verwijzingen op. Body: { oasUrl } of { oasBody }.", + "operationId": "bundleOAS", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OasInput" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "headers": { + "API-Version": { + "description": "De API-versie van de response", + "explode": false, + "schema": { + "type": "string" + }, + "style": "simple" + } + } + }, + "404": { + "$ref": "#/components/responses/404" + } + }, + "security": [ + { + "apiKey": [], + "clientCredentials": [] + } + ], + "summary": "Bundle OpenAPI", + "tags": [ + "Tools" + ], + "x-eov-operation-handler": "controllers/ToolsController" + } + }, + "/v1/oas/generate": { + "post": { + "description": "Genereert een boilerplate OpenAPI specificatie op basis van JSON-invoer. Body: { oasUrl } of { oasBody } (stringified JSON).", + "operationId": "generateOAS", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OasInput" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "headers": { + "API-Version": { + "description": "De API-versie van de response", + "explode": false, + "schema": { + "type": "string" + }, + "style": "simple" + } + }, + "content": { + "application/json": { + "schema": { + "type": "object" + } + } + } + }, + "404": { + "$ref": "#/components/responses/404" + } + }, + "security": [ + { + "apiKey": [], + "clientCredentials": [] + } + ], + "summary": "Generate OpenAPI", + "tags": [ + "Tools" + ], + "x-eov-operation-handler": "controllers/ToolsController", + "x-original-operationId": "GenerateOAS" + } + }, + "/v1/oas/validate": { + "post": { + "description": "Valideert een OpenAPI specificatie met de DON ADR ruleset. Standaard wordt ruleset 2.1 gebruikt; geef targetVersion \"2.0\" of \"2.1\" mee om een versie te kiezen. Body: { oasUrl } of { oasBody } (stringified JSON of YAML).", + "operationId": "validatorOpenAPIPost", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OasInput" + } + } + } + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsLintResult" + } + } + }, + "description": "OK", + "headers": { + "API-Version": { + "description": "De API-versie van de response", + "explode": false, + "schema": { + "type": "string" + }, + "style": "simple" + } + } + }, + "404": { + "$ref": "#/components/responses/404" + } + }, + "security": [ + { + "apiKey": [], + "clientCredentials": [] + } + ], + "summary": "Validate OpenAPI (POST)", + "tags": [ + "Tools" + ], + "x-eov-operation-handler": "controllers/ToolsController" + } + }, + "/v1/oas/postman": { + "post": { + "description": "Converteert OpenAPI naar Postman Collection JSON. Body: { oasUrl } of { oasBody } (stringified JSON of YAML).", + "operationId": "createPostmanCollection", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OasInput" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "headers": { + "API-Version": { + "description": "De API-versie van de response", + "explode": false, + "schema": { + "type": "string" + }, + "style": "simple" + } + } + }, + "404": { + "$ref": "#/components/responses/404" + } + }, + "security": [ + { + "apiKey": [], + "clientCredentials": [] + } + ], + "summary": "Maak Postman-collectie (POST)", + "tags": [ + "Tools" + ], + "x-eov-operation-handler": "controllers/ToolsController", + "x-original-operationId": "CreatePostmanCollection" + } + } + }, + "components": { + "headers": { + "API-Version": { + "description": "De API-versie van de response", + "explode": false, + "schema": { + "example": "1.0.0", + "type": "string" + }, + "style": "simple" + } + }, + "responses": { + "404": { + "description": "Resource does not exist", + "headers": { + "API-Version": { + "$ref": "#/components/headers/API-Version" + } + } + } + }, + "schemas": { + "OasInput": { + "example": { + "oasUrl": "oasUrl", + "oasBody": "oasBody", + "targetVersion": "3.1" + }, + "properties": { + "oasBody": { + "type": "string" + }, + "oasUrl": { + "type": "string" + }, + "targetVersion": { + "description": "Doelversie. Voor conversie: 3.0 of 3.1. Voor validatie: 2.0 of 2.1.", + "type": "string" + } + }, + "type": "object" + }, + "ModelsKeycloakClientResult": { + "example": { + "apiKey": "apiKey" + }, + "properties": { + "apiKey": { + "type": "string" + } + }, + "type": "object" + }, + "ModelsLintMessage": { + "example": { + "severity": "severity", + "createdAt": "2000-01-23T04:56:07.000Z", + "code": "code", + "id": "id", + "infos": [ + { + "path": "path", + "lintMessageId": "lintMessageId", + "id": "id", + "message": "message" + }, + { + "path": "path", + "lintMessageId": "lintMessageId", + "id": "id", + "message": "message" + } + ] + }, + "properties": { + "code": { + "type": "string" + }, + "createdAt": { + "format": "date-time", + "type": "string" + }, + "id": { + "type": "string" + }, + "infos": { + "items": { + "$ref": "#/components/schemas/ModelsLintMessageInfo" + }, + "type": "array" + }, + "severity": { + "type": "string" + } + }, + "type": "object" + }, + "ModelsLintMessageInfo": { + "example": { + "path": "path", + "lintMessageId": "lintMessageId", + "id": "id", + "message": "message" + }, + "properties": { + "id": { + "type": "string" + }, + "lintMessageId": { + "type": "string" + }, + "message": { + "type": "string" + }, + "path": { + "type": "string" + } + }, + "type": "object" + }, + "ModelsLintResult": { + "example": { + "createdAt": "2000-01-23T04:56:07.000Z", + "score": 6, + "failures": 0, + "successes": true, + "rulesetVersion": "2.1", + "messages": [ + { + "severity": "severity", + "createdAt": "2000-01-23T04:56:07.000Z", + "code": "code", + "id": "id", + "infos": [ + { + "path": "path", + "lintMessageId": "lintMessageId", + "id": "id", + "message": "message" + }, + { + "path": "path", + "lintMessageId": "lintMessageId", + "id": "id", + "message": "message" + } + ] + }, + { + "severity": "severity", + "createdAt": "2000-01-23T04:56:07.000Z", + "code": "code", + "id": "id", + "infos": [ + { + "path": "path", + "lintMessageId": "lintMessageId", + "id": "id", + "message": "message" + }, + { + "path": "path", + "lintMessageId": "lintMessageId", + "id": "id", + "message": "message" + } + ] + } + ], + "id": "id", + "apiId": "apiId" + }, + "properties": { + "apiId": { + "type": "string" + }, + "createdAt": { + "format": "date-time", + "type": "string" + }, + "failures": { + "format": "int32", + "type": "integer" + }, + "id": { + "type": "string" + }, + "messages": { + "items": { + "$ref": "#/components/schemas/ModelsLintMessage" + }, + "type": "array" + }, + "score": { + "format": "int32", + "type": "integer" + }, + "successes": { + "type": "boolean" + }, + "rulesetVersion": { + "description": "De gebruikte ruleset-versie voor validatie.", + "type": "string" + } + }, + "type": "object" + }, + "UntrustClientInput": { + "example": { + "email": "email" + }, + "properties": { + "email": { + "type": "string" + } + }, + "type": "object" + } + }, + "securitySchemes": { + "apiKey": { + "in": "header", + "name": "X-Api-Key", + "type": "apiKey", + "description": "Read-only API keys for tools endpoints can be requested at https://apis.developer.overheid.nl/apis/key-aanvragen." + }, + "clientCredentials": { + "flows": { + "clientCredentials": { + "scopes": { + "tools": "Access to tools endpoints" + }, + "tokenUrl": "https://auth.developer.overheid.nl/realms/don/protocol/openid-connect/token" + } + }, + "type": "oauth2" + } + } + } +} diff --git a/app/api-implementations.ts b/app/api-implementations.ts new file mode 100644 index 0000000..b1482c8 --- /dev/null +++ b/app/api-implementations.ts @@ -0,0 +1,9 @@ +import { Type } from '@nestjs/common'; +import { ToolsApi } from '../api'; + +/** + * Provide this type to {@link ApiModule} to provide your API implementations +**/ +export type ApiImplementations = { + toolsApi: Type +}; diff --git a/app/api.module.ts b/app/api.module.ts new file mode 100644 index 0000000..e5e617c --- /dev/null +++ b/app/api.module.ts @@ -0,0 +1,65 @@ +import { DynamicModule, HttpException, Module, Provider } from '@nestjs/common'; +import { ApiImplementations } from './api-implementations' +import { ToolsApi } from '../api'; +import { ToolsApiController } from '../controllers'; + +const createNotImplementedProvider = (apiName: string) => + new Proxy( + {}, + { + get: (_target, property) => { + if (typeof property !== 'string') return undefined; + if ( + property === 'then' || + property === 'onModuleInit' || + property === 'onApplicationBootstrap' || + property === 'onModuleDestroy' || + property === 'beforeApplicationShutdown' || + property === 'onApplicationShutdown' + ) { + return undefined; + } + return () => { + throw new HttpException(`Operation ${property} is not implemented in ${apiName}`, 501); + }; + }, + }, + ); + +export type ApiModuleConfiguration = { + /** + * your Api implementations + */ + apiImplementations?: Partial, + /** + * additional Providers that may be used by your implementations + */ + providers?: Provider[], +} + +@Module({}) +export class ApiModule { + static forRoot(configuration: ApiModuleConfiguration = {}): DynamicModule { + const providers: Provider[] = [ + configuration.apiImplementations?.toolsApi + ? { + provide: ToolsApi, + useClass: configuration.apiImplementations.toolsApi, + } + : { + provide: ToolsApi, + useValue: createNotImplementedProvider('ToolsApi'), + }, + ...(configuration.providers || []), + ]; + + return { + module: ApiModule, + controllers: [ + ToolsApiController, + ], + providers: [...providers], + exports: [...providers] + } + } +} diff --git a/app/index.ts b/app/index.ts new file mode 100644 index 0000000..e8c0bed --- /dev/null +++ b/app/index.ts @@ -0,0 +1,672 @@ +import "reflect-metadata"; +import { readFileSync } from "node:fs"; +import { join } from "node:path"; +import { ArgumentsHost, Catch, ExceptionFilter, HttpException, Module } from "@nestjs/common"; +import { NestFactory } from "@nestjs/core"; +import { FastifyAdapter, NestFastifyApplication } from "@nestjs/platform-fastify"; +import cors from "@fastify/cors"; +import addFormats from "ajv-formats"; +import { OpenAPIBackend } from "openapi-backend"; +import type { Operation, Request as OpenAPIRequest } from "openapi-backend"; +import type Ajv from "ajv"; +import { ApiModule } from "./api.module"; +import { ToolsApiService } from "../implementation/tools-api.service"; + +const yaml = require("js-yaml") as { load(input: string): unknown }; + +type RuntimeOpenAPIRequest = OpenAPIRequest & { + path: string; +}; + +type RuntimeOperation = Operation & { + operationId?: string; + path: string; + method: string; + requestBody?: { + content?: Record; + }; + responses?: Record; +}; + +type RuntimeRequest = { + url: string; + method: string; + query?: unknown; + params?: unknown; + headers: Record; +}; + +type RuntimeReply = { + statusCode: number; + status(statusCode: number): RuntimeReply; + type(contentType: string): RuntimeReply; + header(name: string, value: unknown): RuntimeReply; + getHeader(name: string): unknown; + getHeaders(): Record; + send(payload: unknown): unknown; +}; + +type ValidationError = { + instancePath?: string; + schemaPath?: string; + keyword?: string; + params?: unknown; + message?: string; +}; + +type ProblemError = { + in: string; + location: string; + code: string; + detail: string; +}; + +const parseInt10 = (value: string | undefined, fallback: number): number => { + if (!value) return fallback; + const parsed = Number.parseInt(value, 10); + return Number.isFinite(parsed) ? parsed : fallback; +}; + +const parseBoolean = (value: string | undefined): boolean => { + if (!value) return false; + return ["1", "true", "yes", "on"].includes(value.toLowerCase()); +}; + +const statusText = (status: number): string => { + const texts: Record = { + 400: "Bad Request", + 401: "Unauthorized", + 403: "Forbidden", + 404: "Not Found", + 405: "Method Not Allowed", + 409: "Conflict", + 415: "Unsupported Media Type", + 422: "Unprocessable Entity", + 429: "Too Many Requests", + 500: "Internal Server Error", + 501: "Not Implemented", + 502: "Bad Gateway", + 503: "Service Unavailable", + 504: "Gateway Timeout", + }; + return texts[status] ?? "Unknown Error"; +}; + +const toProblem = (status: number, title: string, errors?: ProblemError[]) => ({ + title, + status, + ...(errors?.length ? { errors } : {}), +}); + +const toProblemErrors = (errors: ValidationError[] | undefined): ProblemError[] | undefined => { + if (!errors?.length) return undefined; + const bodyErrors = errors.filter((error) => ["body", "requestBody"].includes(error.instancePath?.split("/").filter(Boolean)[0] ?? "")); + if (bodyErrors.length > 0) { + return [ + { + in: "body", + location: "body", + code: "body", + detail: bodyErrors.map((error) => error.message ?? "Invalid request body").join("\n"), + }, + ]; + } + + return errors.map((error) => { + const params = typeof error.params === "object" && error.params !== null ? (error.params as Record) : {}; + const additionalProperty = typeof params.additionalProperty === "string" ? params.additionalProperty : undefined; + const location = additionalProperty ?? error.instancePath?.split("/").filter(Boolean).pop() ?? ""; + const source = error.instancePath?.split("/").filter(Boolean)[0] ?? ""; + const sourceMap: Record = { + body: "body", + headers: "header", + path: "path", + params: "path", + query: "query", + cookies: "cookie", + }; + return { + in: sourceMap[source] ?? "request", + location, + code: error.keyword ?? "validation", + detail: error.message ?? "Invalid value", + }; + }); +}; + +const isRecord = (value: unknown): value is Record => + typeof value === "object" && value !== null && !Array.isArray(value); + +const resolveJsonPointer = (document: unknown, pointer: string): unknown => { + if (!pointer.startsWith("#/")) return undefined; + return pointer + .slice(2) + .split("/") + .map((part) => part.replace(/~1/g, "/").replace(/~0/g, "~")) + .reduce((current, part) => (isRecord(current) ? current[part] : undefined), document); +}; + +const resolveRef = (document: unknown, value: unknown): unknown => { + if (!isRecord(value) || typeof value.$ref !== "string") return value; + return resolveJsonPointer(document, value.$ref) ?? value; +}; + +const getResponseObject = (document: unknown, operation: RuntimeOperation | undefined, statusCode: number): Record | undefined => { + if (!operation?.responses) return undefined; + const responses = operation.responses; + const response = responses[String(statusCode)] ?? responses[`${Math.floor(statusCode / 100)}XX`] ?? responses.default; + const resolved = resolveRef(document, response); + return isRecord(resolved) ? resolved : undefined; +}; + +const getResponseContentTypes = (responseObject: Record | undefined): string[] => { + const content = responseObject?.content; + return isRecord(content) ? Object.keys(content) : []; +}; + +const getResponseMediaObject = ( + document: unknown, + responseObject: Record | undefined, + contentType: string | undefined, +): Record | undefined => { + if (!contentType || !isRecord(responseObject?.content)) return undefined; + const content = responseObject.content; + const mediaType = Object.keys(content).find((candidate) => mediaTypeMatches(contentType, candidate)); + const mediaObject = mediaType ? resolveRef(document, content[mediaType]) : undefined; + return isRecord(mediaObject) ? mediaObject : undefined; +}; + +const acceptsMediaType = (acceptHeader: unknown, mediaType: string): boolean => { + if (typeof acceptHeader !== "string" || acceptHeader.trim() === "" || acceptHeader.includes("*/*")) return true; + return acceptHeader + .split(",") + .map((part) => part.split(";")[0]?.trim() ?? "") + .some((accepted) => mediaTypeMatches(mediaType, accepted)); +}; + +const chooseResponseContentType = (request: RuntimeRequest, responseObject: Record | undefined): string | undefined => { + const contentTypes = getResponseContentTypes(responseObject); + if (contentTypes.length === 0) return undefined; + return contentTypes.find((mediaType) => acceptsMediaType(request.headers.accept, mediaType)) ?? contentTypes[0]; +}; + +const getSchemaType = (schema: unknown): string | undefined => { + if (!isRecord(schema)) return undefined; + if (typeof schema.type === "string") return schema.type; + if (Array.isArray(schema.type)) return schema.type.find((type) => type !== "null"); + if (schema.format === "date-time" || schema.format === "date" || schema.format === "uri") return "string"; + return undefined; +}; + +const getExampleValue = (document: unknown, value: unknown): unknown => { + const resolved = resolveRef(document, value); + if (!isRecord(resolved)) return undefined; + if ("value" in resolved) return resolved.value; + return undefined; +}; + +const firstDefined = (...values: unknown[]): unknown => values.find((value) => value !== undefined); + +const mockFromSchema = (document: unknown, schema: unknown, seen = new Set()): unknown => { + const resolvedSchema = resolveRef(document, schema); + if (!isRecord(resolvedSchema)) return {}; + if (seen.has(resolvedSchema)) return {}; + seen.add(resolvedSchema); + + const directValue = firstDefined(resolvedSchema.example, resolvedSchema.default, resolvedSchema.const); + if (directValue !== undefined) return directValue; + if (Array.isArray(resolvedSchema.examples) && resolvedSchema.examples.length > 0) return resolvedSchema.examples[0]; + if (Array.isArray(resolvedSchema.enum) && resolvedSchema.enum.length > 0) { + return resolvedSchema.enum.find((value) => value !== null) ?? resolvedSchema.enum[0]; + } + + if (Array.isArray(resolvedSchema.allOf)) { + const values = resolvedSchema.allOf.map((item) => mockFromSchema(document, item, seen)); + if (values.every(isRecord)) return Object.assign({}, ...values); + return values.find((value) => value !== undefined && value !== null) ?? {}; + } + + const union = Array.isArray(resolvedSchema.oneOf) + ? resolvedSchema.oneOf + : Array.isArray(resolvedSchema.anyOf) + ? resolvedSchema.anyOf + : undefined; + if (union) { + const preferred = union.find((item) => getSchemaType(resolveRef(document, item)) !== "null") ?? union[0]; + return mockFromSchema(document, preferred, seen); + } + + const schemaType = getSchemaType(resolvedSchema); + if (schemaType === "array") return [mockFromSchema(document, resolvedSchema.items, seen)]; + if (schemaType === "object" || isRecord(resolvedSchema.properties)) { + const properties = isRecord(resolvedSchema.properties) ? resolvedSchema.properties : {}; + return Object.fromEntries(Object.entries(properties).map(([name, propertySchema]) => [name, mockFromSchema(document, propertySchema, seen)])); + } + if (schemaType === "integer" || schemaType === "number") return 0; + if (schemaType === "boolean") return true; + if (schemaType === "null") return null; + + if (resolvedSchema.format === "email") return "user@example.com"; + if (resolvedSchema.format === "uri" || resolvedSchema.format === "url") return "https://example.com/path"; + if (resolvedSchema.format === "uuid") return "3fa85f64-5717-4562-b3fc-2c963f66afa6"; + if (resolvedSchema.format === "date") return "1970-01-01"; + if (resolvedSchema.format === "date-time") return "1970-01-01T00:00:00.000Z"; + return "string"; +}; + +const getMediaExample = (document: unknown, mediaObject: Record | undefined): unknown => { + if (!mediaObject) return undefined; + if ("example" in mediaObject) return mediaObject.example; + if (isRecord(mediaObject.examples)) { + for (const example of Object.values(mediaObject.examples)) { + const value = getExampleValue(document, example); + if (value !== undefined) return value; + } + } + return undefined; +}; + +const selectMockStatusCode = (operation: RuntimeOperation): number => { + const responseCodes = Object.keys(operation.responses ?? {}); + const successCode = responseCodes.find((code) => /^[23]\d\d$/.test(code)); + if (successCode) return Number.parseInt(successCode, 10); + const numericCode = responseCodes.find((code) => /^\d\d\d$/.test(code)); + return numericCode ? Number.parseInt(numericCode, 10) : 200; +}; + +const mockResponseForOperation = ( + document: unknown, + request: RuntimeRequest, + operation: RuntimeOperation, +): { status: number; body: unknown; contentType?: string } => { + const status = selectMockStatusCode(operation); + const responseObject = getResponseObject(document, operation, status); + const contentType = chooseResponseContentType(request, responseObject); + const mediaObject = getResponseMediaObject(document, responseObject, contentType); + const example = getMediaExample(document, mediaObject); + const schema = mediaObject?.schema; + return { + status, + contentType, + body: example !== undefined ? example : schema !== undefined ? mockFromSchema(document, schema) : undefined, + }; +}; + +const firstQueryValue = (query: unknown, names: string[]): string | undefined => { + if (!isRecord(query)) return undefined; + const lowerCaseEntries = new Map(Object.entries(query).map(([key, value]) => [key.toLowerCase(), value])); + for (const name of names) { + const value = lowerCaseEntries.get(name.toLowerCase()); + if (Array.isArray(value)) return value[0] === undefined ? undefined : String(value[0]); + if (value !== undefined) return String(value); + } + return undefined; +}; + +const firstPathValue = (params: unknown, names: string[]): string | undefined => { + if (!isRecord(params)) return undefined; + const lowerCaseEntries = new Map(Object.entries(params).map(([key, value]) => [key.toLowerCase(), value])); + for (const name of names) { + const value = lowerCaseEntries.get(name.toLowerCase()); + if (value !== undefined) return String(value); + } + return undefined; +}; + +const buildPaginationLink = (request: RuntimeRequest): string => { + const url = new URL(request.url, "http://localhost"); + const currentPage = Number.parseInt(firstQueryValue(request.query, ["page", "Page"]) ?? "1", 10) || 1; + const perPage = Number.parseInt(firstQueryValue(request.query, ["perPage", "PerPage"]) ?? "20", 10) || 20; + const totalPages = Math.max(currentPage, 1); + const withPage = (page: number) => { + const nextUrl = new URL(url.toString()); + nextUrl.searchParams.set("page", String(page)); + nextUrl.searchParams.set("perPage", String(perPage)); + return `${nextUrl.pathname}${nextUrl.search}`; + }; + return [`<${withPage(1)}>; rel="first"`, `<${withPage(totalPages)}>; rel="last"`].join(", "); +}; + +const mockPagination = (request: RuntimeRequest): { currentPage: number; perPage: number; totalPages: number; totalCount: number } => { + const currentPage = Math.max(Number.parseInt(firstQueryValue(request.query, ["page", "Page"]) ?? "1", 10) || 1, 1); + const perPage = Math.max(Number.parseInt(firstQueryValue(request.query, ["perPage", "PerPage"]) ?? "20", 10) || 20, 1); + const totalPages = Math.max(currentPage, 1); + return { + currentPage, + perPage, + totalPages, + totalCount: (totalPages - 1) * perPage + 1, + }; +}; + +const mockHeaderValue = (name: string, schema: unknown, request: RuntimeRequest, apiVersion: string | undefined): string => { + const normalizedName = name.toLowerCase(); + const pagination = mockPagination(request); + if (normalizedName === "api-version") return apiVersion ?? "1.0.0"; + if (normalizedName === "link") return buildPaginationLink(request); + if (normalizedName === "total-count") return String(pagination.totalCount); + if (normalizedName === "current-page") return String(pagination.currentPage); + if (normalizedName === "per-page") return String(pagination.perPage); + if (normalizedName === "total-pages") return String(pagination.totalPages); + if (normalizedName === "oas-version") return firstPathValue(request.params, ["version", "oasVersion", "OASVersion"]) ?? "mock"; + if (normalizedName === "oas-source") return "mock"; + + const schemaType = getSchemaType(schema); + if (schemaType === "integer" || schemaType === "number") return "1"; + if (schemaType === "boolean") return "true"; + return "string"; +}; + +const applyDeclaredResponseMetadata = ( + document: unknown, + request: RuntimeRequest, + reply: RuntimeReply, + operation: RuntimeOperation | undefined, + statusCode: number, + apiVersion: string | undefined, +) => { + const responseObject = getResponseObject(document, operation, statusCode); + const declaredHeaders = responseObject?.headers; + if (isRecord(declaredHeaders)) { + for (const [headerName, headerDefinition] of Object.entries(declaredHeaders)) { + if (reply.getHeader(headerName) !== undefined) continue; + const resolvedHeader = resolveRef(document, headerDefinition); + const schema = isRecord(resolvedHeader) ? resolveRef(document, resolvedHeader.schema) : undefined; + reply.header(headerName, mockHeaderValue(headerName, schema, request, apiVersion)); + } + } + + if (apiVersion && !reply.getHeader("API-Version")) reply.header("API-Version", apiVersion); + + const contentType = chooseResponseContentType(request, responseObject); + if (contentType && !reply.getHeader("content-type")) reply.type(contentType); +}; + +const sendProblem = ( + document: unknown, + request: RuntimeRequest, + reply: RuntimeReply, + operation: RuntimeOperation | undefined, + status: number, + title: string, + apiVersion: string | undefined, + errors?: ValidationError[], +) => { + applyDeclaredResponseMetadata(document, request, reply.status(status), operation, status, apiVersion); + if (!reply.getHeader("content-type")) reply.type("application/problem+json"); + return reply.send(toProblem(status, title, toProblemErrors(errors))); +}; + +const escapeRegExp = (input: string): string => input.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + +const openApiPathToRegExp = (path: string): RegExp => { + const source = path + .split("/") + .map((part) => (part.startsWith("{") && part.endsWith("}") ? "[^/]+" : escapeRegExp(part))) + .join("/"); + return new RegExp(`^${source}/?$`); +}; + +const toHeaderRecord = (headers: Record): Record => { + const result: Record = {}; + for (const [key, value] of Object.entries(headers)) { + if (Array.isArray(value)) result[key] = value.map(String); + else if (value !== undefined) result[key] = String(value); + } + return result; +}; + +const hasOpenApiPath = (document: unknown, path: string): boolean => + typeof document === "object" && + document !== null && + "paths" in document && + typeof (document as { paths?: unknown }).paths === "object" && + (document as { paths: Record }).paths !== null && + path in (document as { paths: Record }).paths; + +const isJsonLikeContentType = (contentType: unknown): boolean => + typeof contentType === "string" && /\bjson\b/i.test(contentType); + +const normalizeMediaType = (contentType: string): string => contentType.split(";")[0]?.trim().toLowerCase() ?? ""; + +const mediaTypeMatches = (actual: string, expected: string): boolean => { + const normalizedActual = normalizeMediaType(actual); + const normalizedExpected = normalizeMediaType(expected); + if (normalizedActual === normalizedExpected) return true; + if (normalizedExpected === "*/*") return true; + const [expectedType, expectedSubtype] = normalizedExpected.split("/"); + const [actualType, actualSubtype] = normalizedActual.split("/"); + if (!expectedType || !expectedSubtype || !actualType || !actualSubtype) return false; + if (expectedSubtype === "*") return expectedType === actualType; + return expectedSubtype.startsWith("*+") && actualSubtype.endsWith(expectedSubtype.slice(1)) && expectedType === actualType; +}; + +const hasUnsupportedRequestMediaType = (operation: RuntimeOperation, contentType: unknown, body: unknown): boolean => { + const allowedMediaTypes = Object.keys(operation.requestBody?.content ?? {}); + if (allowedMediaTypes.length === 0 || body === undefined) return false; + if (typeof contentType !== "string" || contentType.trim() === "") return true; + return !allowedMediaTypes.some((mediaType) => mediaTypeMatches(contentType, mediaType)); +}; + +const isDeclaredResponseStatus = (operation: RuntimeOperation, statusCode: number): boolean => { + const responses = operation.responses ?? {}; + return String(statusCode) in responses || `${Math.floor(statusCode / 100)}XX` in responses || "default" in responses; +}; + +const chooseDeclaredResponseStatus = (operation: RuntimeOperation | undefined, statusCode: number): number => { + if (!operation || statusCode >= 400 || isDeclaredResponseStatus(operation, statusCode)) return statusCode; + return selectMockStatusCode(operation); +}; + +@Catch() +class ProblemDetailsFilter implements ExceptionFilter { + catch(error: unknown, host: ArgumentsHost) { + const context = host.switchToHttp(); + const request = context.getRequest<{ url?: string }>(); + const reply = context.getResponse(); + const status = error instanceof HttpException ? error.getStatus() : 500; + const response = error instanceof HttpException ? error.getResponse() : undefined; + const detail = + typeof response === "object" && response !== null && "message" in response + ? Array.isArray((response as { message?: unknown }).message) + ? (response as { message: unknown[] }).message.join(", ") + : String((response as { message?: unknown }).message) + : error instanceof Error + ? error.message + : statusText(status); + + reply.status(status).type("application/problem+json").send(toProblem(status, detail)); + } +} + +@Module({ + imports: [ + ApiModule.forRoot({ + apiImplementations: { + toolsApi: ToolsApiService, + }, + }), + ], +}) +class AppModule {} + +export const createApp = async () => { + const app = await NestFactory.create(AppModule, new FastifyAdapter({ bodyLimit: 14 * 1024 * 1024 })); + await app.register(cors); + app.useGlobalFilters(new ProblemDetailsFilter()); + + const openapiYaml = readFileSync(join(process.cwd(), "api", "openapi.yaml"), "utf8"); + const openapiDocument = yaml.load(openapiYaml); + const openapi = new OpenAPIBackend({ + definition: openapiDocument as never, + quick: true, + validate: true, + coerceTypes: true, + ajvOpts: { + allErrors: true, + strict: false, + }, + customizeAjv: (ajv: Ajv) => addFormats(ajv), + }); + await openapi.init(); + + const apiVersion = + typeof openapiDocument === "object" && openapiDocument !== null && "info" in openapiDocument + ? (openapiDocument as { info?: { version?: string } }).info?.version + : undefined; + const mockResponses = parseBoolean(process.env.OPENAPI_MOCK); + const validateResponses = parseBoolean(process.env.OPENAPI_VALIDATE_RESPONSES); + const operations = openapi.getOperations() as RuntimeOperation[]; + const operationPaths = operations.map((operation) => ({ + operation, + pathPattern: openApiPathToRegExp(operation.path), + })); + const generatedOpenApiPaths = new Set(); + if (!hasOpenApiPath(openapiDocument, "/openapi.yaml")) generatedOpenApiPaths.add("/openapi.yaml"); + if (!hasOpenApiPath(openapiDocument, "/openapi.json")) generatedOpenApiPaths.add("/openapi.json"); + const isGeneratedOpenApiEndpoint = (path: string): boolean => generatedOpenApiPaths.has(path.split("?")[0] ?? path); + + const fastify = app.getHttpAdapter().getInstance(); + + fastify.addHook("preValidation", async (request, reply) => { + if (isGeneratedOpenApiEndpoint(request.url)) return; + + const openapiRequest: RuntimeOpenAPIRequest = { + method: request.method, + path: request.url, + body: request.body, + query: request.query as Record | string | undefined, + headers: toHeaderRecord(request.headers), + }; + const operation = openapi.matchOperation(openapiRequest) as RuntimeOperation | undefined; + + if (!operation) { + const requestPath = request.url.split("?")[0] ?? request.url; + const allowedMethods = operationPaths + .filter(({ pathPattern }) => pathPattern.test(requestPath)) + .map(({ operation: candidate }) => candidate.method.toUpperCase()); + + if (allowedMethods.length > 0) { + reply.header("Allow", [...new Set(allowedMethods)].sort().join(", ")); + return sendProblem( + openapiDocument, + request as RuntimeRequest, + reply as RuntimeReply, + undefined, + 405, + `Method ${request.method} is not allowed for ${requestPath}`, + apiVersion, + ); + } + return; + } + + const operationId = operation.operationId; + if (hasUnsupportedRequestMediaType(operation, request.headers["content-type"], request.body)) { + return sendProblem( + openapiDocument, + request as RuntimeRequest, + reply as RuntimeReply, + operation, + 415, + "Request content type is not supported by the OpenAPI operation", + apiVersion, + ); + } + + const validation = openapi.validateRequest(openapiRequest, operationId); + if (!validation.valid) { + const status = validation.errors?.some((error) => error.keyword === "contentType") ? 415 : 400; + return sendProblem( + openapiDocument, + request as RuntimeRequest, + reply as RuntimeReply, + operation, + status, + "Request validation failed", + apiVersion, + validation.errors ?? undefined, + ); + } + + (request as { openapiOperation?: RuntimeOperation }).openapiOperation = operation; + + if (mockResponses) { + const mocked = mockResponseForOperation(openapiDocument, request as RuntimeRequest, operation); + applyDeclaredResponseMetadata( + openapiDocument, + request as RuntimeRequest, + reply.status(mocked.status) as RuntimeReply, + operation, + mocked.status, + apiVersion, + ); + if (mocked.contentType && !reply.getHeader("content-type")) reply.type(mocked.contentType); + return reply.send(mocked.body); + } + }); + + fastify.addHook("onSend", async (_request, reply, payload) => { + const request = _request as RuntimeRequest & { openapiOperation?: RuntimeOperation }; + const statusCode = chooseDeclaredResponseStatus(request.openapiOperation, reply.statusCode); + if (statusCode !== reply.statusCode) reply.status(statusCode); + applyDeclaredResponseMetadata(openapiDocument, request, reply as RuntimeReply, request.openapiOperation, statusCode, apiVersion); + return payload; + }); + fastify.addHook("onSend", async (request, reply, payload) => { + if (!validateResponses) return payload; + if (isGeneratedOpenApiEndpoint(request.url)) return payload; + + const operation = (request as { openapiOperation?: RuntimeOperation }).openapiOperation; + const operationId = operation?.operationId; + if (!operationId) return payload; + + const statusCode = reply.statusCode; + if (!isDeclaredResponseStatus(operation, statusCode)) { + reply.status(502).type("application/problem+json"); + return JSON.stringify(toProblem(502, `Response status ${statusCode} is not declared in the OpenAPI specification`)); + } + + const contentType = reply.getHeader("content-type"); + const responseBody = + typeof payload === "string" && isJsonLikeContentType(contentType) + ? JSON.parse(payload) + : payload; + const bodyValidation = openapi.validateResponse(responseBody, operationId, statusCode); + if (!bodyValidation.valid) { + reply.status(502).type("application/problem+json"); + return JSON.stringify( + toProblem(502, "Response body does not match the OpenAPI specification", toProblemErrors(bodyValidation.errors ?? undefined)), + ); + } + + const headerValidation = openapi.validateResponseHeaders(reply.getHeaders(), operationId, { + statusCode, + }); + if (!headerValidation.valid) { + reply.status(502).type("application/problem+json"); + return JSON.stringify( + toProblem(502, "Response headers do not match the OpenAPI specification", toProblemErrors(headerValidation.errors ?? undefined)), + ); + } + + return payload; + }); + if (generatedOpenApiPaths.has("/openapi.yaml")) { + fastify.get("/openapi.yaml", async (_request, reply) => reply.type("text/yaml; charset=utf-8").send(openapiYaml)); + } + if (generatedOpenApiPaths.has("/openapi.json")) { + fastify.get("/openapi.json", async () => openapiDocument); + } + + return app; +}; + +export const bootstrap = async () => { + const app = await createApp(); + await app.listen(parseInt10(process.env.PORT, 1338), process.env.HOST ?? "0.0.0.0"); +}; + +if (require.main === module) { + void bootstrap(); +} diff --git a/biome.json b/biome.json index fac7c27..322be84 100644 --- a/biome.json +++ b/biome.json @@ -1,5 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/2.4.13/schema.json", + "$schema": "https://biomejs.dev/schemas/2.4.16/schema.json", "formatter": { "indentStyle": "space", "indentWidth": 2, @@ -22,5 +22,8 @@ "formatter": { "quoteStyle": "double" } + }, + "files": { + "includes": ["src/**", "test/**", "*.json", "*.ts"] } } diff --git a/config.js b/config.js deleted file mode 100644 index f047887..0000000 --- a/config.js +++ /dev/null @@ -1,24 +0,0 @@ -const path = require("node:path"); - -const parseEnvBoolean = (value) => { - if (value === undefined || value === null) { - return false; - } - return ["1", "true", "yes", "on"].includes(String(value).toLowerCase()); -}; - -const config = { - ROOT_DIR: __dirname, - URL_PORT: 1338, - URL_PATH: "https://api.developer.overheid.nl", - BASE_VERSION: "/tools/v1", - CONTROLLER_DIRECTORY: path.join(__dirname, "controllers"), - PROJECT_DIR: __dirname, - USE_MOCKS: parseEnvBoolean(process.env.USE_MOCKS) || parseEnvBoolean(process.env.MOCKS_ENABLED), -}; -config.OPENAPI_JSON = path.join(config.ROOT_DIR, "api", "openapi.json"); -config.FULL_PATH = `${config.URL_PATH}:${config.URL_PORT}/${config.BASE_VERSION}`; -config.FILE_UPLOAD_PATH = path.join(config.PROJECT_DIR, "uploaded_files"); -config.MOCK_DIR = path.join(config.PROJECT_DIR, "mocks"); - -module.exports = config; diff --git a/controllers/Controller.js b/controllers/Controller.js deleted file mode 100644 index 7524b93..0000000 --- a/controllers/Controller.js +++ /dev/null @@ -1,256 +0,0 @@ -const fs = require("node:fs"); -const path = require("node:path"); -const config = require("../config"); -const Service = require("../services/Service"); -const logger = require("../logger"); - -class Controller { - static getStatusText(status) { - const statusTexts = { - 400: "Bad Request", - 401: "Unauthorized", - 403: "Forbidden", - 404: "Not Found", - 405: "Method Not Allowed", - 409: "Conflict", - 422: "Unprocessable Entity", - 429: "Too Many Requests", - 500: "Internal Server Error", - }; - return statusTexts[status] || "Unknown Error"; - } - - static sendResponse(response, payload) { - /** - * The default response-code is 200. We want to allow to change that. in That case, - * payload will be an object consisting of a code and a payload. If not customized - * send 200 and the payload as received in this method. - */ - response.status(payload.code || 200); - if (payload.headers && typeof payload.headers === "object") { - Object.entries(payload.headers).forEach(([header, value]) => { - if (value !== undefined) { - response.set(header, value); - } - }); - } - const responsePayload = payload.payload !== undefined ? payload.payload : payload; - if (Buffer.isBuffer(responsePayload)) { - if (!response.get("Content-Type")) { - response.set("Content-Type", "application/octet-stream"); - } - response.send(responsePayload); - return; - } - if (responsePayload !== null && typeof responsePayload === "object") { - response.json(responsePayload); - } else if (responsePayload !== undefined) { - response.end(responsePayload); - } else { - response.end(); - } - } - - static sendError(response, error) { - const status = error.code || 500; - const reason = error.message || error.error?.message || "Unexpected error"; - const detail = error.detail || reason; - let invalidParams = []; - if (Array.isArray(error.invalidParams)) { - invalidParams = error.invalidParams; - } else if (error.field !== undefined || error.reason !== undefined) { - invalidParams = [ - { - name: error.field || "body", - reason: error.reason || detail, - }, - ]; - } - - const problem = { - type: `https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/${status}`, - title: Controller.getStatusText(status), - status, - detail, - instance: error.instance || "body", - }; - if (invalidParams.length > 0) { - problem.invalidParams = invalidParams; - } - - logger.error(`Request failed (${status} ${Controller.getStatusText(status)}): ${reason}`, { - detail, - invalidParams, - errorMessage: error?.message, - stack: error?.stack, - }); - - response.status(status).json(problem); - } - - /** - * Files have been uploaded to the directory defined by config.js as upload directory - * Files have a temporary name, that was saved as 'filename' of the file object that is - * referenced in request.files array. - * This method finds the file and changes it to the file name that was originally called - * when it was uploaded. To prevent files from being overwritten, a timestamp is added between - * the filename and its extension - * @param request - * @param fieldName - * @returns {string} - */ - static collectFile(request, fieldName) { - let uploadedFileName = ""; - if (request.files && request.files.length > 0) { - const fileObject = request.files.find((file) => file.fieldname === fieldName); - if (fileObject) { - const fileArray = fileObject.originalname.split("."); - const extension = fileArray.pop(); - fileArray.push(`_${Date.now()}`); - uploadedFileName = `${fileArray.join("")}.${extension}`; - fs.renameSync( - path.join(config.FILE_UPLOAD_PATH, fileObject.filename), - path.join(config.FILE_UPLOAD_PATH, uploadedFileName), - ); - } - } - return uploadedFileName; - } - - static getRequestBodyName(request) { - const codeGenDefinedBodyName = request.openapi.schema["x-codegen-request-body-name"]; - if (codeGenDefinedBodyName !== undefined) { - return codeGenDefinedBodyName; - } - const refObjectPath = request.openapi.schema.requestBody.content["application/json"].schema.$ref; - if (refObjectPath !== undefined && refObjectPath.length > 0) { - return refObjectPath.substr(refObjectPath.lastIndexOf("/") + 1); - } - return "body"; - } - - static aliasRequestBodyParam(params, bodyName, value) { - if (!bodyName || value === undefined) { - return params; - } - const result = { ...params }; - if (!Object.hasOwn(result, bodyName)) { - result[bodyName] = value; - } - if (!Object.hasOwn(result, "body")) { - result.body = value; - } - const sanitizedName = Service.sanitizeOperationId(bodyName); - if (sanitizedName && !Object.hasOwn(result, sanitizedName)) { - result[sanitizedName] = value; - } - const lowerCaseName = bodyName.charAt(0).toLowerCase() + bodyName.slice(1); - if (lowerCaseName && !Object.hasOwn(result, lowerCaseName)) { - result[lowerCaseName] = value; - } - if (value && typeof value === "object" && !Array.isArray(value)) { - Object.keys(value).forEach((key) => { - if (!Object.hasOwn(result, key)) { - result[key] = value[key]; - } - }); - } - return result; - } - - static collectRequestParams(request) { - let requestParams = {}; - if (request.openapi.schema.requestBody !== null) { - const { content } = request.openapi.schema.requestBody; - if (content["application/json"] !== undefined) { - const requestBodyName = Controller.getRequestBodyName(request); - const schemaObject = content["application/json"].schema || {}; - let schemaDefinition = schemaObject; - if (schemaObject.$ref) { - const resolved = Service.resolveRef(schemaObject.$ref); - if (resolved) { - schemaDefinition = resolved; - } - } - const requiredProperties = Array.isArray(schemaDefinition.required) ? schemaDefinition.required : []; - const payload = request.body || {}; - if (requiredProperties.length > 0) { - const missing = requiredProperties.filter((prop) => payload[prop] === undefined); - if (missing.length > 0) { - throw Service.rejectResponse( - { - message: `Missing required properties: ${missing.join(", ")}`, - field: requestBodyName, - detail: `Missing required properties: ${missing.join(", ")}`, - }, - 400, - ); - } - } - const declaredProperties = schemaDefinition?.properties ? Object.keys(schemaDefinition.properties) : []; - const allowAdditional = (() => { - if (schemaDefinition && Object.hasOwn(schemaDefinition, "additionalProperties")) { - return schemaDefinition.additionalProperties !== false; - } - return false; - })(); - if (!allowAdditional) { - const unknownProperties = Object.keys(payload).filter((prop) => !declaredProperties.includes(prop)); - if (unknownProperties.length > 0) { - throw Service.rejectResponse( - { - message: `Unknown properties: ${unknownProperties.join(", ")}`, - field: requestBodyName, - detail: `Unknown properties: ${unknownProperties.join(", ")}`, - }, - 400, - ); - } - } - if (Object.keys(payload).length > 0) { - requestParams = Controller.aliasRequestBodyParam( - { - ...requestParams, - [requestBodyName]: payload, - }, - requestBodyName, - payload, - ); - } - } else if (content["multipart/form-data"] !== undefined) { - Object.keys(content["multipart/form-data"].schema.properties).forEach((property) => { - const propertyObject = content["multipart/form-data"].schema.properties[property]; - if (propertyObject.format !== undefined && propertyObject.format === "binary") { - requestParams[property] = Controller.collectFile(request, property); - } else { - requestParams[property] = request.body[property]; - } - }); - } - } - - if (request.openapi.schema.parameters !== undefined) { - request.openapi.schema.parameters.forEach((param) => { - if (param.in === "path") { - requestParams[param.name] = request.openapi.pathParams[param.name]; - } else if (param.in === "query") { - requestParams[param.name] = request.query[param.name]; - } else if (param.in === "header") { - requestParams[param.name] = request.headers[param.name]; - } - }); - } - return requestParams; - } - - static async handleRequest(request, response, serviceOperation) { - try { - const serviceResponse = await serviceOperation(Controller.collectRequestParams(request)); - Controller.sendResponse(response, serviceResponse); - } catch (error) { - Controller.sendError(response, error); - } - } -} - -module.exports = Controller; diff --git a/controllers/ToolsApi.controller.ts b/controllers/ToolsApi.controller.ts new file mode 100644 index 0000000..bc43007 --- /dev/null +++ b/controllers/ToolsApi.controller.ts @@ -0,0 +1,52 @@ +import { Body, Controller, DefaultValuePipe, Post, Inject, Param, ParseIntPipe, ParseFloatPipe, Query, Req, Res } from '@nestjs/common'; +import type { FastifyReply } from 'fastify'; +import { Observable } from 'rxjs'; +import { Cookies, Headers } from '../decorators'; +import { ToolsApi } from '../api'; +import { ModelsKeycloakClientResult, ModelsLintResult, OasInput, UntrustClientInput, } from '../models'; + +@Controller() +export class ToolsApiController { + constructor(@Inject(ToolsApi) private readonly toolsApi: ToolsApi) {} + + @Post('/v1/arazzo/markdown') + arazzoMarkdown(@Body() oasInput: OasInput | undefined, @Req() request: Request, @Res({ passthrough: true }) reply: FastifyReply): string | Promise | Observable { + return this.toolsApi.arazzoMarkdown(oasInput, request, reply); + } + + @Post('/v1/arazzo/mermaid') + arazzoMermaid(@Body() oasInput: OasInput | undefined, @Req() request: Request, @Res({ passthrough: true }) reply: FastifyReply): string | Promise | Observable { + return this.toolsApi.arazzoMermaid(oasInput, request, reply); + } + + @Post('/v1/oas/bundle') + bundleOAS(@Body() oasInput: OasInput | undefined, @Req() request: Request, @Res({ passthrough: true }) reply: FastifyReply): void | Promise | Observable { + return this.toolsApi.bundleOAS(oasInput, request, reply); + } + + @Post('/v1/oas/convert') + convertOAS(@Body() oasInput: OasInput | undefined, @Req() request: Request, @Res({ passthrough: true }) reply: FastifyReply): void | Promise | Observable { + return this.toolsApi.convertOAS(oasInput, request, reply); + } + + @Post('/v1/oas/postman') + createPostmanCollection(@Body() oasInput: OasInput | undefined, @Req() request: Request, @Res({ passthrough: true }) reply: FastifyReply): void | Promise | Observable { + return this.toolsApi.createPostmanCollection(oasInput, request, reply); + } + + @Post('/v1/oas/generate') + generateOAS(@Body() oasInput: OasInput | undefined, @Req() request: Request, @Res({ passthrough: true }) reply: FastifyReply): object | Promise | Observable { + return this.toolsApi.generateOAS(oasInput, request, reply); + } + + @Post('/v1/auth/clients') + untrustClient(@Body() untrustClientInput: UntrustClientInput | undefined, @Req() request: Request, @Res({ passthrough: true }) reply: FastifyReply): ModelsKeycloakClientResult | Promise | Observable { + return this.toolsApi.untrustClient(untrustClientInput, request, reply); + } + + @Post('/v1/oas/validate') + validatorOpenAPIPost(@Body() oasInput: OasInput | undefined, @Req() request: Request, @Res({ passthrough: true }) reply: FastifyReply): ModelsLintResult | Promise | Observable { + return this.toolsApi.validatorOpenAPIPost(oasInput, request, reply); + } + +} diff --git a/controllers/ToolsController.js b/controllers/ToolsController.js deleted file mode 100644 index 50248e8..0000000 --- a/controllers/ToolsController.js +++ /dev/null @@ -1,53 +0,0 @@ -/** - * The ToolsController file is a very simple one, which does not need to be changed manually, - * unless there's a case where business logic routes the request to an entity which is not - * the service. - * The heavy lifting of the Controller item is done in Request.js - that is where request - * parameters are extracted and sent to the service, and where response is handled. - */ - -const Controller = require("./Controller"); -const service = require("../services/ToolsService"); - -const arazzoMarkdown = async (request, response) => { - await Controller.handleRequest(request, response, service.arazzoMarkdown); -}; - -const arazzoMermaid = async (request, response) => { - await Controller.handleRequest(request, response, service.arazzoMermaid); -}; - -const convertOAS = async (request, response) => { - await Controller.handleRequest(request, response, service.convertOAS); -}; - -const createPostmanCollection = async (request, response) => { - await Controller.handleRequest(request, response, service.createPostmanCollection); -}; - -const bundleOAS = async (request, response) => { - await Controller.handleRequest(request, response, service.bundleOAS); -}; - -const generateOAS = async (request, response) => { - await Controller.handleRequest(request, response, service.generateOAS); -}; - -const untrustClient = async (request, response) => { - await Controller.handleRequest(request, response, service.untrustClient); -}; - -const validatorOpenAPIPost = async (request, response) => { - await Controller.handleRequest(request, response, service.validatorOpenAPIPost); -}; - -module.exports = { - arazzoMarkdown, - arazzoMermaid, - convertOAS, - createPostmanCollection, - bundleOAS, - generateOAS, - untrustClient, - validatorOpenAPIPost, -}; diff --git a/controllers/index.js b/controllers/index.js deleted file mode 100644 index a389b0d..0000000 --- a/controllers/index.js +++ /dev/null @@ -1,5 +0,0 @@ -const ToolsController = require("./ToolsController"); - -module.exports = { - ToolsController, -}; diff --git a/controllers/index.ts b/controllers/index.ts new file mode 100644 index 0000000..bca7f6c --- /dev/null +++ b/controllers/index.ts @@ -0,0 +1 @@ +export * from './ToolsApi.controller'; diff --git a/decorators/cookies-decorator.ts b/decorators/cookies-decorator.ts new file mode 100644 index 0000000..fe8ce15 --- /dev/null +++ b/decorators/cookies-decorator.ts @@ -0,0 +1,24 @@ +import { createParamDecorator, ExecutionContext } from '@nestjs/common'; + +/** +* A decorator function for retrieving cookies from the request object in an HTTP context. +* +* This decorator only works, if the framework specific cookie middleware is installed and enabled. +* - For Express, you need to use the `cookie-parser` middleware. +* - For Fastify, you need to use the `@fastify/cookie` plugin. +* +* Consult https://docs.nestjs.com/techniques/cookies for further information +* +* Usage: +* ``` +* @Get() +* findAll(@Cookies('name') name: string) {} +* ``` +*/ +export const Cookies = createParamDecorator((cookieName: string, ctx: ExecutionContext) => { + const request = ctx.switchToHttp().getRequest(); + if (!cookieName) { + return { ...request.cookies, ...request.signedCookies }; + } + return request.cookies?.[cookieName] ?? request.signedCookies?.[cookieName]; +}); \ No newline at end of file diff --git a/decorators/headers-decorator.ts b/decorators/headers-decorator.ts new file mode 100644 index 0000000..85bd979 --- /dev/null +++ b/decorators/headers-decorator.ts @@ -0,0 +1,16 @@ +import { createParamDecorator, ExecutionContext } from '@nestjs/common'; + +/** +* A decorator function for retrieving headers from the request object in an HTTP context. +* Workaround for enabling PipeTransformers on Headers (see https://github.com/nestjs/nest/issues/356) +* +* Usage: +* ``` +* @Get() +* findAll(@Headers('name') name: string) {} +* ``` +*/ +export const Headers = createParamDecorator((headerName: string, ctx: ExecutionContext) => { + const request = ctx.switchToHttp().getRequest(); + return headerName ? request.headers?.[headerName.toLowerCase()] : request.headers; +}); \ No newline at end of file diff --git a/decorators/index.ts b/decorators/index.ts new file mode 100644 index 0000000..4bd1d7b --- /dev/null +++ b/decorators/index.ts @@ -0,0 +1,2 @@ +export * from './cookies-decorator'; +export * from './headers-decorator'; \ No newline at end of file diff --git a/expressServer.js b/expressServer.js deleted file mode 100644 index 9500c7b..0000000 --- a/expressServer.js +++ /dev/null @@ -1,265 +0,0 @@ -const http = require("node:http"); -const fs = require("node:fs"); -const path = require("node:path"); -const express = require("express"); -const cors = require("cors"); -const bodyParser = require("body-parser"); -const OpenApiValidator = require("express-openapi-validator"); -const logger = require("./logger"); -const config = require("./config"); - -class ExpressServer { - static sanitizeOperationId(operationId) { - if (!operationId || typeof operationId !== "string") { - return null; - } - let result = operationId.trim(); - if (result.length === 0) { - return null; - } - result = result.replace(/[_-]+/g, " "); - result = result.replace(/[^a-zA-Z0-9_$]+/g, " "); - result = result - .split(" ") - .filter((segment) => segment.length > 0) - .map((segment, index) => { - if (index === 0) { - return segment; - } - return segment.charAt(0).toUpperCase() + segment.slice(1); - }) - .join(""); - result = result.replace(/^[^a-zA-Z_$]+/, ""); - if (result.length === 0) { - return null; - } - return result.charAt(0).toLowerCase() + result.slice(1); - } - - static sanitizeTagName(tagName) { - if (!tagName || typeof tagName !== "string") { - return null; - } - let result = tagName.trim(); - if (result.length === 0) { - return null; - } - result = result.replace(/[_-]+/g, " "); - result = result.replace(/[^a-zA-Z0-9_$]+/g, " "); - const parts = result - .split(" ") - .filter((segment) => segment.length > 0) - .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1)); - if (parts.length === 0) { - return null; - } - return parts.join(""); - } - - static normalizeOperationIds(schema) { - if (!schema || !schema.paths) { - return; - } - const methods = ["get", "put", "post", "delete", "options", "head", "patch", "trace"]; - for (const pathKey of Object.keys(schema.paths)) { - const pathItem = schema.paths[pathKey]; - for (const method of methods) { - const operation = pathItem[method]; - if (operation?.operationId) { - const normalizedId = ExpressServer.sanitizeOperationId(operation.operationId); - if (normalizedId && normalizedId !== operation.operationId) { - operation["x-original-operationId"] = operation.operationId; - operation.operationId = normalizedId; - } - } - } - } - } - - constructor(port, openApiJsonPath) { - this.port = port; - this.app = express(); - try { - this.schema = JSON.parse(fs.readFileSync(openApiJsonPath, "utf8")); - if (this.schema?.components) { - const { components } = this.schema; - const componentMirrors = [ - "schemas", - "responses", - "parameters", - "examples", - "requestBodies", - "headers", - "securitySchemes", - "links", - "callbacks", - "pathItems", - ]; - for (const key of componentMirrors) { - if (!this.schema[key] && components[key]) { - this.schema[key] = components[key]; - } - } - } - ExpressServer.normalizeOperationIds(this.schema); - } catch (e) { - logger.error("failed to start Express Server", e.message); - } - this.setupMiddleware(); - } - - static getStatusText(status) { - const statusTexts = { - 400: "Bad Request", - 401: "Unauthorized", - 403: "Forbidden", - 404: "Not Found", - 405: "Method Not Allowed", - 409: "Conflict", - 422: "Unprocessable Entity", - 429: "Too Many Requests", - 500: "Internal Server Error", - 501: "Not Implemented", - 502: "Bad Gateway", - 503: "Service Unavailable", - 504: "Gateway Timeout", - }; - return statusTexts[status] || "Unknown Error"; - } - - setupMiddleware() { - // this.setupAllowedMedia(); - this.app.use(cors()); - this.app.use(bodyParser.json({ limit: "14MB" })); - this.app.use(express.json()); - this.app.use(express.urlencoded({ extended: false })); - this.app.use((_req, res, next) => { - res.set("API-Version", this.schema.info.version); - next(); - }); - const sendOpenApiSpec = (_req, res) => res.json(this.schema); - this.app.get("/v1/openapi.json", sendOpenApiSpec); - this.app.use( - OpenApiValidator.middleware({ - apiSpec: this.schema, - validateApiSpec: false, - validateSecurity: false, - validateRequests: { - coerceTypes: false, - allowUnknownBodyProperties: false, - }, - operationHandlers: { - basePath: path.join(__dirname), - }, - fileUploader: { dest: config.FILE_UPLOAD_PATH }, - }), - ); - ExpressServer.registerRoutes(this.app, this.schema); - } - - static toExpressPath(openApiPath) { - return openApiPath.replace(/{/g, ":").replace(/}/g, ""); - } - - static resolveOperationHandler(operation) { - let handlerRef = operation["x-eov-operation-handler"]; - if (!handlerRef && operation.tags?.length > 0) { - const tagName = ExpressServer.sanitizeTagName(operation.tags[0]); - if (tagName) { - handlerRef = `controllers/${tagName}Controller`; - } - } - if (!handlerRef) { - logger.warn(`No handler reference found for operation ${operation.operationId}`); - return null; - } - const normalizedRef = handlerRef.replace(/\\/g, "/"); - const modulePath = normalizedRef.endsWith(".js") - ? path.join(__dirname, normalizedRef) - : path.join(__dirname, `${normalizedRef}.js`); - if (!fs.existsSync(modulePath)) { - logger.warn(`Handler module missing for ${operation.operationId}: ${modulePath}`); - return null; - } - // eslint-disable-next-line global-require, import/no-dynamic-require - const controllerModule = require(modulePath); - const handler = controllerModule[operation.operationId]; - if (typeof handler !== "function") { - logger.warn(`Handler function ${operation.operationId} not found in ${modulePath}`); - return null; - } - return handler; - } - - static registerRoutes(app, schema) { - if (!schema || !schema.paths) { - return; - } - const methods = ["get", "put", "post", "delete", "options", "head", "patch", "trace"]; - for (const pathKey of Object.keys(schema.paths)) { - const expressPath = ExpressServer.toExpressPath(pathKey); - const pathItem = schema.paths[pathKey]; - for (const method of methods) { - const operation = pathItem[method]; - if (!operation) { - continue; - } - const handler = ExpressServer.resolveOperationHandler(operation); - if (!handler) { - continue; - } - app[method](expressPath, async (req, res, next) => { - logger.info(`Incoming request for ${method.toUpperCase()} ${expressPath}`); - req.openapi = req.openapi || {}; - req.openapi.schema = req.openapi.schema || operation; - req.openapi.pathParams = req.openapi.pathParams || req.params; - try { - await Promise.resolve(handler(req, res, next)); - } catch (error) { - next(error); - } - }); - } - } - } - - launch() { - // eslint-disable-next-line no-unused-vars - this.app.use((err, req, res, _next) => { - // format errors using RFC 7807 Problem Details format - const status = err.status || 500; - const problemDetails = { - type: `https://httpstatuses.com/${status}`, - title: ExpressServer.getStatusText(status), - status, - detail: err.message || err.toString(), - }; - - // Add instance URI if available - if (req.originalUrl) { - problemDetails.instance = req.originalUrl; - } - - // Add additional error details if available - if (err.status === 400 && err.errors && Array.isArray(err.errors) && err.errors.length > 0) { - problemDetails.invalidParams = err.errors; - } - - // Set the proper content type for problem+json - res.set("Content-Type", "application/problem+json"); - res.status(status).json(problemDetails); - }); - - http.createServer(this.app).listen(this.port); - console.log(`Listening on port ${this.port}`); - } - - async close() { - if (this.server !== undefined) { - await this.server.close(); - console.log(`Server on port ${this.port} shut down`); - } - } -} - -module.exports = ExpressServer; diff --git a/implementation/tools-api.service.ts b/implementation/tools-api.service.ts new file mode 100644 index 0000000..18cb8e5 --- /dev/null +++ b/implementation/tools-api.service.ts @@ -0,0 +1,74 @@ +import { BadRequestException, Injectable } from "@nestjs/common"; +import type { FastifyReply } from "fastify"; +import type { OasInput, UntrustedClientInput, ValidateInput } from "@developer-overheid-nl/don-tools-logic"; +import { ToolsApi } from "../api"; +import type { ModelsKeycloakClientResult, ModelsLintResult } from "../models"; + +const setHeaders = (reply: FastifyReply, headers: Record) => { + for (const [name, value] of Object.entries(headers)) reply.header(name, value); +}; + +const importEsm = new Function("specifier", "return import(specifier)") as (specifier: string) => Promise; +const loadLogic = () => + import("@developer-overheid-nl/don-tools-logic").catch(() => + importEsm("@developer-overheid-nl/don-tools-logic"), + ); + +const asBadRequest = async (operation: () => Promise): Promise => { + try { + return await operation(); + } catch (error) { + throw new BadRequestException(error instanceof Error ? error.message : "Request validation failed"); + } +}; + +@Injectable() +export class ToolsApiService extends ToolsApi { + async arazzoMarkdown(oasInput: OasInput | undefined, _request: Request, reply: FastifyReply): Promise { + const { arazzoMarkdown } = await loadLogic(); + reply.type("text/markdown; charset=utf-8"); + return asBadRequest(() => arazzoMarkdown(oasInput as OasInput)); + } + + async arazzoMermaid(oasInput: OasInput | undefined, _request: Request, reply: FastifyReply): Promise { + const { arazzoMermaid } = await loadLogic(); + reply.type("text/plain; charset=utf-8"); + return asBadRequest(() => arazzoMermaid(oasInput as OasInput)); + } + + async bundleOAS(oasInput: OasInput | undefined, _request: Request, reply: FastifyReply): Promise { + const { bundleOAS } = await loadLogic(); + const result = await asBadRequest(() => bundleOAS(oasInput as OasInput)); + setHeaders(reply, result.headers); + return result.rawBody as unknown as void; + } + + async convertOAS(oasInput: OasInput | undefined, _request: Request, reply: FastifyReply): Promise { + const { convertOAS } = await loadLogic(); + const result = await asBadRequest(() => convertOAS(oasInput as OasInput)); + setHeaders(reply, result.headers); + return result.rawBody as unknown as void; + } + + async createPostmanCollection(oasInput: OasInput | undefined, _request: Request, reply: FastifyReply): Promise { + const { createPostmanCollection } = await loadLogic(); + const result = await asBadRequest(() => createPostmanCollection(oasInput as OasInput)); + setHeaders(reply, result.headers); + return result.rawBody as unknown as void; + } + + async generateOAS(oasInput: OasInput | undefined): Promise { + const { generateOAS } = await loadLogic(); + return asBadRequest(() => generateOAS(oasInput as OasInput)); + } + + async untrustClient(untrustClientInput: UntrustedClientInput | undefined): Promise { + const { untrustedClient } = await loadLogic(); + return asBadRequest(() => untrustedClient(untrustClientInput as UntrustedClientInput)) as Promise; + } + + async validatorOpenAPIPost(oasInput: OasInput | undefined): Promise { + const { validatorOpenAPIPost } = await loadLogic(); + return asBadRequest(() => validatorOpenAPIPost(oasInput as ValidateInput)) as Promise; + } +} diff --git a/index.js b/index.js deleted file mode 100644 index 4f1f314..0000000 --- a/index.js +++ /dev/null @@ -1,34 +0,0 @@ -const fs = require("node:fs"); -const path = require("node:path"); - -const loadLocalEnvFile = () => { - if (typeof process.loadEnvFile !== "function") { - return; - } - const envPath = path.join(__dirname, ".env"); - if (!fs.existsSync(envPath)) { - return; - } - process.loadEnvFile(envPath); -}; - -loadLocalEnvFile(); - -const config = require("./config"); -const logger = require("./logger"); -const ExpressServer = require("./expressServer"); - -let expressServer; - -const launchServer = async () => { - try { - expressServer = new ExpressServer(config.URL_PORT, config.OPENAPI_JSON); - expressServer.launch(); - logger.info("Express server running"); - } catch (error) { - logger.error("Express Server failure", error.message); - await expressServer?.close?.(); - } -}; - -launchServer().catch((e) => logger.error(e)); diff --git a/logger.js b/logger.js deleted file mode 100644 index 7f119b2..0000000 --- a/logger.js +++ /dev/null @@ -1,18 +0,0 @@ -const { transports, createLogger, format } = require("winston"); - -const logger = createLogger({ - level: "info", - format: format.combine(format.timestamp(), format.json()), - defaultMeta: { service: "user-service" }, - transports: [ - new transports.Console(), - new transports.File({ filename: "error.log", level: "error", timestamp: true }), - new transports.File({ filename: "combined.log", timestamp: true }), - ], -}); - -if (process.env.NODE_ENV !== "production") { - logger.add(new transports.Console({ format: format.simple() })); -} - -module.exports = logger; diff --git a/models/index.ts b/models/index.ts new file mode 100644 index 0000000..7b5a4f5 --- /dev/null +++ b/models/index.ts @@ -0,0 +1,17 @@ +export * from './models-keycloak-client-result'; +export * from './models-lint-message'; +export * from './models-lint-message-info'; +export * from './models-lint-result'; +export * from './oas-input'; +export * from './untrust-client-input'; + +export {}; + +declare global { + type ModelsKeycloakClientResult = import('./models-keycloak-client-result').ModelsKeycloakClientResult; + type ModelsLintMessage = import('./models-lint-message').ModelsLintMessage; + type ModelsLintMessageInfo = import('./models-lint-message-info').ModelsLintMessageInfo; + type ModelsLintResult = import('./models-lint-result').ModelsLintResult; + type OasInput = import('./oas-input').OasInput; + type UntrustClientInput = import('./untrust-client-input').UntrustClientInput; +} diff --git a/models/models-keycloak-client-result.ts b/models/models-keycloak-client-result.ts new file mode 100644 index 0000000..4ae98d2 --- /dev/null +++ b/models/models-keycloak-client-result.ts @@ -0,0 +1,4 @@ +export interface ModelsKeycloakClientResult { + apiKey?: string; +} + diff --git a/models/models-lint-message-info.ts b/models/models-lint-message-info.ts new file mode 100644 index 0000000..97b555b --- /dev/null +++ b/models/models-lint-message-info.ts @@ -0,0 +1,7 @@ +export interface ModelsLintMessageInfo { + id?: string; + lintMessageId?: string; + message?: string; + path?: string; +} + diff --git a/models/models-lint-message.ts b/models/models-lint-message.ts new file mode 100644 index 0000000..dd559e7 --- /dev/null +++ b/models/models-lint-message.ts @@ -0,0 +1,8 @@ +export interface ModelsLintMessage { + code?: string; + createdAt?: string; + id?: string; + infos?: Array; + severity?: string; +} + diff --git a/models/models-lint-result.ts b/models/models-lint-result.ts new file mode 100644 index 0000000..13136f5 --- /dev/null +++ b/models/models-lint-result.ts @@ -0,0 +1,14 @@ +export interface ModelsLintResult { + apiId?: string; + createdAt?: string; + failures?: number; + id?: string; + messages?: Array; + score?: number; + successes?: boolean; + /** + * De gebruikte ruleset-versie voor validatie. + */ + rulesetVersion?: string; +} + diff --git a/models/oas-input.ts b/models/oas-input.ts new file mode 100644 index 0000000..9d2c87e --- /dev/null +++ b/models/oas-input.ts @@ -0,0 +1,9 @@ +export interface OasInput { + oasBody?: string; + oasUrl?: string; + /** + * Doelversie. Voor conversie: 3.0 of 3.1. Voor validatie: 2.0 of 2.1. + */ + targetVersion?: string; +} + diff --git a/models/untrust-client-input.ts b/models/untrust-client-input.ts new file mode 100644 index 0000000..b2d1fe2 --- /dev/null +++ b/models/untrust-client-input.ts @@ -0,0 +1,4 @@ +export interface UntrustClientInput { + email?: string; +} + diff --git a/package-lock.json b/package-lock.json index 5ab9d79..61753d8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,49 +9,44 @@ "version": "1.0.0", "license": "EUPL-1.2", "dependencies": { - "@apiture/openapi-down-convert": "^0.14.2", - "@developer-overheid-nl/adr-rulesets": "github:developer-overheid-nl/adr-rulesets#da1327dfcc83ed130b1fe5aaa282b7bfba537aee", - "@redocly/cli": "^2.30.3", - "@scalar/openapi-upgrader": "^0.2.7", - "@stoplight/spectral-parsers": "^1.0.5", - "@stoplight/spectral-rulesets": "^1.22.1", - "@stoplight/spectral-runtime": "^1.1.5", - "body-parser": "^2.2.2", - "case-anything": "^3.1.2", - "cors": "^2.8.6", - "express": "^5.2.1", - "express-openapi-validator": "^5.6.2", - "js-yaml": "^4.1.1", - "jszip": "^3.10.1", - "openapi-to-postmanv2": "^6.0.1", - "winston": "^3.19.0" + "@developer-overheid-nl/don-tools-logic": "^0.0.1", + "@fastify/cors": "^11.2.0", + "@nestjs/common": "^11.0.0", + "@nestjs/core": "^11.0.0", + "@nestjs/platform-fastify": "^11.0.0", + "ajv-formats": "^3.0.1", + "fastify": "^5.8.5", + "js-yaml": "^4.2.0", + "openapi-backend": "^5.17.0", + "reflect-metadata": "^0.2.2", + "rxjs": "^7.8.1" }, "devDependencies": { - "@biomejs/biome": "^2.4.13" + "@biomejs/biome": "^2.4.16", + "@types/node": "^25.9.2", + "tsx": "^4.22.4", + "typescript": "^6.0.3", + "vite": "^8.0.16", + "vitest": "^4.1.8" } }, "node_modules/@apidevtools/json-schema-ref-parser": { - "version": "14.2.1", - "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-14.2.1.tgz", - "integrity": "sha512-HmdFw9CDYqM6B25pqGBpNeLCKvGPlIx1EbLrVL0zPvj50CJQUHyBNBw45Muk0kEIkogo1VZvOKHajdMuAzSxRg==", + "version": "11.9.3", "license": "MIT", "dependencies": { + "@jsdevtools/ono": "^7.1.3", + "@types/json-schema": "^7.0.15", "js-yaml": "^4.1.0" }, "engines": { - "node": ">= 20" + "node": ">= 16" }, "funding": { "url": "https://github.com/sponsors/philsturgeon" - }, - "peerDependencies": { - "@types/json-schema": "^7.0.15" } }, "node_modules/@apiture/openapi-down-convert": { "version": "0.14.2", - "resolved": "https://registry.npmjs.org/@apiture/openapi-down-convert/-/openapi-down-convert-0.14.2.tgz", - "integrity": "sha512-vT3eqOEmJ4KZ2qojycEV0zzFBPDrkwntyfnWi8/WMaag8jvGN4osIdVRuwxWcK6AvQr32ohrpcLGqEZ+ZHVNcw==", "license": "ISC", "dependencies": { "commander": "^9.4.1", @@ -62,31 +57,29 @@ "openapi-down-convert": "lib/src/cli.js" } }, - "node_modules/@apiture/openapi-down-convert/node_modules/commander": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", - "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", - "license": "MIT", + "node_modules/@apiture/openapi-down-convert/node_modules/typescript": { + "version": "4.9.5", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, "engines": { - "node": "^12.20.0 || >=14" + "node": ">=4.2.0" } }, "node_modules/@asyncapi/specs": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/@asyncapi/specs/-/specs-6.10.0.tgz", - "integrity": "sha512-vB5oKLsdrLUORIZ5BXortZTlVyGWWMC1Nud/0LtgxQ3Yn2738HigAD6EVqScvpPsDUI/bcLVsYEXN4dtXQHVng==", + "version": "6.11.1", "license": "Apache-2.0", "dependencies": { "@types/json-schema": "^7.0.11" } }, "node_modules/@babel/code-frame": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", - "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "version": "7.29.7", "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.28.5", + "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -95,27 +88,21 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "version": "7.29.7", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/runtime": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", - "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", + "version": "7.29.7", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@biomejs/biome": { - "version": "2.4.13", - "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.4.13.tgz", - "integrity": "sha512-gLXOwkOBBg0tr7bDsqlkIh4uFeKuMjxvqsrb1Tukww1iDmHcfr4Uu8MoQxp0Rcte+69+osRNWXwHsu/zxT6XqA==", + "version": "2.4.16", "dev": true, "license": "MIT OR Apache-2.0", "bin": { @@ -129,20 +116,18 @@ "url": "https://opencollective.com/biome" }, "optionalDependencies": { - "@biomejs/cli-darwin-arm64": "2.4.13", - "@biomejs/cli-darwin-x64": "2.4.13", - "@biomejs/cli-linux-arm64": "2.4.13", - "@biomejs/cli-linux-arm64-musl": "2.4.13", - "@biomejs/cli-linux-x64": "2.4.13", - "@biomejs/cli-linux-x64-musl": "2.4.13", - "@biomejs/cli-win32-arm64": "2.4.13", - "@biomejs/cli-win32-x64": "2.4.13" + "@biomejs/cli-darwin-arm64": "2.4.16", + "@biomejs/cli-darwin-x64": "2.4.16", + "@biomejs/cli-linux-arm64": "2.4.16", + "@biomejs/cli-linux-arm64-musl": "2.4.16", + "@biomejs/cli-linux-x64": "2.4.16", + "@biomejs/cli-linux-x64-musl": "2.4.16", + "@biomejs/cli-win32-arm64": "2.4.16", + "@biomejs/cli-win32-x64": "2.4.16" } }, "node_modules/@biomejs/cli-darwin-arm64": { - "version": "2.4.13", - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.4.13.tgz", - "integrity": "sha512-2KImO1jhNFBa2oWConyr0x6flxbQpGKv6902uGXpYM62Xyem8U80j441SyUJ8KyngsmKbQjeIv1q2CQfDkNnYg==", + "version": "2.4.16", "cpu": [ "arm64" ], @@ -157,9 +142,9 @@ } }, "node_modules/@biomejs/cli-darwin-x64": { - "version": "2.4.13", - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.4.13.tgz", - "integrity": "sha512-BKrJklbaFN4p1Ts4kPBczo+PkbsHQg57kmJ+vON9u2t6uN5okYHaSr7h/MutPCWQgg2lglaWoSmm+zhYW+oOkg==", + "version": "2.4.16", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.4.16.tgz", + "integrity": "sha512-xFCqGPwYusQJp4N4NJLi1XJiZqjwFdjhT+KqtNy+Ug3qgfczqnTa6MSDvxJF6TkuDLoYJItMapz6tAf7kCekFw==", "cpu": [ "x64" ], @@ -174,13 +159,16 @@ } }, "node_modules/@biomejs/cli-linux-arm64": { - "version": "2.4.13", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.4.13.tgz", - "integrity": "sha512-NzkUDSqfvMBrPplKgVr3aXLHZ2NEELvvF4vZxXulEylKWIGqlvNEcwUcj9OLrn75TD3lJ/GIqCVlBwd1MZCuYQ==", + "version": "2.4.16", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.4.16.tgz", + "integrity": "sha512-2kFb4//jxfZaP6D+Rj5VkHkxgyD9EoRAVBEQb8PKRv+s4NO2zYNJKXFaJmK1CmhufJOWEfpHKaRbOja7qjmdhQ==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT OR Apache-2.0", "optional": true, "os": [ @@ -191,13 +179,16 @@ } }, "node_modules/@biomejs/cli-linux-arm64-musl": { - "version": "2.4.13", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.4.13.tgz", - "integrity": "sha512-U5MsuBQW25dXaYtqWWSPM3P96H6Y+fHuja3TQpMNnylocHW0tEbtFTDlUj6oM+YJLntvEkQy4grBvQNUD4+RCg==", + "version": "2.4.16", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.4.16.tgz", + "integrity": "sha512-oYxnW0ARfJkr72ezzF2OR8N/rtkgLUQeYtF8cFhVswbknHxtTcmzSsanVJP8yQKnGpGpc2ck6c5zLvHahL6Cbg==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT OR Apache-2.0", "optional": true, "os": [ @@ -208,13 +199,16 @@ } }, "node_modules/@biomejs/cli-linux-x64": { - "version": "2.4.13", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.4.13.tgz", - "integrity": "sha512-Az3ZZedYRBo9EQzNnD9SxFcR1G5QsGo6VEc2hIyVPZ1rdKwee/7E9oeBBZFpE8Z44ekxsDQBqbiWGW5ShOhUSQ==", + "version": "2.4.16", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.4.16.tgz", + "integrity": "sha512-NbcBbi/nJqn5baae6wqRXdS7Gadf2uRpehSh6vMSYpG8OhkXl/Xg8aorWrJ+9VWqAT5ml90alLvorkpMW0nBwQ==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT OR Apache-2.0", "optional": true, "os": [ @@ -225,13 +219,16 @@ } }, "node_modules/@biomejs/cli-linux-x64-musl": { - "version": "2.4.13", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.4.13.tgz", - "integrity": "sha512-Z601MienRgTBDza/+u2CH3RSrWoXo9rtr8NK6A4KJzqGgfxx+H3VlyLgTJ4sRo40T3pIsqpTmiOQEvYzQvBRvQ==", + "version": "2.4.16", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.4.16.tgz", + "integrity": "sha512-iHDS+MCM65DPqWGu+ECC3uoALyj2H7F4nVUPxIPjz/PIl94EUu+EDfGZDzFP+NY1EOPVt9NQvwFqq7HdMmowdg==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT OR Apache-2.0", "optional": true, "os": [ @@ -242,9 +239,9 @@ } }, "node_modules/@biomejs/cli-win32-arm64": { - "version": "2.4.13", - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.4.13.tgz", - "integrity": "sha512-Px9PS2B5/Q183bUwy/5VHqp3J2lzdOCeVGzMpphYfl8oSa7VDCqenBdqWpy6DCy/en4Rbf/Y1RieZF6dJPcc9A==", + "version": "2.4.16", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.4.16.tgz", + "integrity": "sha512-0rgImMsNb5v/chhkIFe3wu7PEFClS6RBAYUijGL9UsYN3PanSaoK24HSSuSJb1pYbYYVjzAyZTl3gtjJ84BM8A==", "cpu": [ "arm64" ], @@ -259,9 +256,9 @@ } }, "node_modules/@biomejs/cli-win32-x64": { - "version": "2.4.13", - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.4.13.tgz", - "integrity": "sha512-tTcMkXyBrmHi9BfrD2VNHs/5rYIUKETqsBlYOvSAABwBkJhSDVb5e7wPukftsQbO3WzQkXe6kaztC6WtUOXSoQ==", + "version": "2.4.16", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.4.16.tgz", + "integrity": "sha512-Kp85jgoBHa05gix6UIRjfCDiUV3w/8VIdZ247VyyO2gEjaw12WEVhdIjlxp/AMzXxqxQwbxNTDVZ3Mwd2RG5rw==", "cpu": [ "x64" ], @@ -275,30 +272,17 @@ "node": ">=14.21.3" } }, - "node_modules/@colors/colors": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", - "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", - "license": "MIT", - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/@dabh/diagnostics": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.8.tgz", - "integrity": "sha512-R4MSXTVnuMzGD7bzHdW2ZhhdPC/igELENcq5IjEverBvq5hn1SXCWcsi6eSsdWP0/Ur+SItRRjAktmdoX/8R/Q==", + "node_modules/@borewit/text-codec": { + "version": "0.2.2", "license": "MIT", - "dependencies": { - "@so-ric/colorspace": "^1.1.6", - "enabled": "2.0.x", - "kuler": "^2.0.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" } }, "node_modules/@developer-overheid-nl/adr-rulesets": { "version": "0.1.0", "resolved": "git+ssh://git@github.com/developer-overheid-nl/adr-rulesets.git#da1327dfcc83ed130b1fe5aaa282b7bfba537aee", - "integrity": "sha512-SUFzrz7JkAJCjq+5NCS+SbbpI9YAqJGbgFv5POTnRrTMMg52U6lDJ/fdkTNyoOyPx2/9rtKlZYdicPKpUzeXtg==", "license": "EUPL-1.2", "dependencies": { "@stoplight/spectral-core": "^1.21.0", @@ -306,368 +290,919 @@ "@stoplight/spectral-rulesets": "^1.22.0" } }, - "node_modules/@emotion/is-prop-valid": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.4.0.tgz", - "integrity": "sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==", - "license": "MIT", + "node_modules/@developer-overheid-nl/don-tools-logic": { + "version": "0.0.1", + "license": "EUPL-1.2", "dependencies": { - "@emotion/memoize": "^0.9.0" - } - }, - "node_modules/@emotion/memoize": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", - "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", - "license": "MIT" - }, - "node_modules/@emotion/unitless": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", - "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==", - "license": "MIT" - }, - "node_modules/@exodus/schemasafe": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@exodus/schemasafe/-/schemasafe-1.3.0.tgz", - "integrity": "sha512-5Aap/GaRupgNx/feGBwLLTVv8OQFfv3pq2lPRzPg9R+IOBnDgghTGW7l7EuVXOvg5cc/xSAlRW8rBrjIC3Nvqw==", - "license": "MIT" - }, - "node_modules/@faker-js/faker": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-5.5.3.tgz", - "integrity": "sha512-R11tGE6yIFwqpaIqcfkcg7AICXzFg14+5h5v0TfF/9+RMDL6jhzCy/pxHVOfbALGdtVYdt6JdR21tuxEgl34dw==", - "deprecated": "Please update to a newer version.", - "license": "MIT" - }, - "node_modules/@humanwhocodes/momoa": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@humanwhocodes/momoa/-/momoa-2.0.4.tgz", - "integrity": "sha512-RE815I4arJFtt+FVeU1Tgp9/Xvecacji8w/V6XtXsWWH/wz/eNkNbhb+ny/+PlVZjV0rxQpRSQKNKE3lcktHEA==", - "license": "Apache-2.0", + "@apiture/openapi-down-convert": "^0.14.2", + "@developer-overheid-nl/adr-rulesets": "github:developer-overheid-nl/adr-rulesets#main", + "@redocly/openapi-core": "^2.32.0", + "@redocly/respect-core": "^2.32.0", + "@scalar/openapi-upgrader": "^0.2.9", + "@stoplight/spectral-core": "^1.23.0", + "@stoplight/spectral-parsers": "^1.0.5", + "case-anything": "^3.1.2", + "js-yaml": "^4.2.0", + "jszip": "^3.10.1", + "openapi-to-postmanv2": "^6.0.1" + }, "engines": { - "node": ">=10.10.0" + "node": ">=22", + "pnpm": ">=11" } }, - "node_modules/@jsdevtools/ono": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", - "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==", - "license": "MIT" - }, - "node_modules/@jsep-plugin/assignment": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@jsep-plugin/assignment/-/assignment-1.3.0.tgz", - "integrity": "sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==", + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "dev": true, "license": "MIT", - "engines": { - "node": ">= 10.16.0" - }, - "peerDependencies": { - "jsep": "^0.4.0||^1.0.0" + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" } }, - "node_modules/@jsep-plugin/regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@jsep-plugin/regex/-/regex-1.0.4.tgz", - "integrity": "sha512-q7qL4Mgjs1vByCaTnDFcBnV9HS7GVPJX5vyVoCgZHNSC9rjwIlmbXG5sUuorR5ndfHAIlJ8pVStxvjXHbNvtUg==", + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, "license": "MIT", - "engines": { - "node": ">= 10.16.0" - }, - "peerDependencies": { - "jsep": "^0.4.0||^1.0.0" + "optional": true, + "dependencies": { + "tslib": "^2.4.0" } }, - "node_modules/@jsep-plugin/ternary": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@jsep-plugin/ternary/-/ternary-1.1.4.tgz", - "integrity": "sha512-ck5wiqIbqdMX6WRQztBL7ASDty9YLgJ3sSAK5ZpBzXeySvFGCzIvM6UiAI4hTZ22fEcYQVV/zhUbNscggW+Ukg==", + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, "license": "MIT", - "engines": { - "node": ">= 10.16.0" - }, - "peerDependencies": { - "jsep": "^0.4.0||^1.0.0" + "optional": true, + "dependencies": { + "tslib": "^2.4.0" } }, - "node_modules/@noble/hashes": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", - "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz", + "integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==", + "cpu": [ + "ppc64" + ], + "dev": true, "license": "MIT", + "optional": true, + "os": [ + "aix" + ], "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" + "node": ">=18" } }, - "node_modules/@opentelemetry/api": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.1.tgz", - "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", - "license": "Apache-2.0", + "node_modules/@esbuild/android-arm": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.0.tgz", + "integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=8.0.0" + "node": ">=18" } }, - "node_modules/@opentelemetry/api-logs": { - "version": "0.214.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.214.0.tgz", - "integrity": "sha512-40lSJeqYO8Uz2Yj7u94/SJWE/wONa7rmMKjI1ZcIjgf3MHNHv1OZUCrCETGuaRF62d5pQD1wKIW+L4lmSMTzZA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "^1.3.0" - }, + "node_modules/@esbuild/android-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.0.tgz", + "integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=8.0.0" + "node": ">=18" } }, - "node_modules/@opentelemetry/context-async-hooks": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-2.6.1.tgz", - "integrity": "sha512-XHzhwRNkBpeP8Fs/qjGrAf9r9PRv67wkJQ/7ZPaBQQ68DYlTBBx5MF9LvPx7mhuXcDessKK2b+DcxqwpgkcivQ==", - "license": "Apache-2.0", + "node_modules/@esbuild/android-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.0.tgz", + "integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" + "node": ">=18" } }, - "node_modules/@opentelemetry/core": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.6.1.tgz", - "integrity": "sha512-8xHSGWpJP9wBxgBpnqGL0R3PbdWQndL1Qp50qrg71+B28zK5OQmUgcDKLJgzyAAV38t4tOyLMGDD60LneR5W8g==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "^1.29.0" - }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.0", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" + "node": ">=18" } }, - "node_modules/@opentelemetry/exporter-trace-otlp-http": { - "version": "0.214.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.214.0.tgz", - "integrity": "sha512-kIN8nTBMgV2hXzV/a20BCFilPZdAIMYYJGSgfMMRm/Xa+07y5hRDS2Vm12A/z8Cdu3Sq++ZvJfElokX2rkgGgw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.6.1", - "@opentelemetry/otlp-exporter-base": "0.214.0", - "@opentelemetry/otlp-transformer": "0.214.0", - "@opentelemetry/resources": "2.6.1", - "@opentelemetry/sdk-trace-base": "2.6.1" - }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.0.tgz", + "integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "node": ">=18" } }, - "node_modules/@opentelemetry/otlp-exporter-base": { - "version": "0.214.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.214.0.tgz", - "integrity": "sha512-u1Gdv0/E9wP+apqWf7Wv2npXmgJtxsW2XL0TEv9FZloTZRuMBKmu8cYVXwS4Hm3q/f/3FuCnPTgiwYvIqRSpRg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.6.1", - "@opentelemetry/otlp-transformer": "0.214.0" - }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.0.tgz", + "integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "node": ">=18" } }, - "node_modules/@opentelemetry/otlp-transformer": { - "version": "0.214.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.214.0.tgz", - "integrity": "sha512-DSaYcuBRh6uozfsWN3R8HsN0yDhCuWP7tOFdkUOVaWD1KVJg8m4qiLUsg/tNhTLS9HUYUcwNpwL2eroLtsZZ/w==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.214.0", - "@opentelemetry/core": "2.6.1", - "@opentelemetry/resources": "2.6.1", - "@opentelemetry/sdk-logs": "0.214.0", - "@opentelemetry/sdk-metrics": "2.6.1", - "@opentelemetry/sdk-trace-base": "2.6.1", - "protobufjs": "^7.0.0" - }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.0.tgz", + "integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "node": ">=18" } }, - "node_modules/@opentelemetry/resources": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.6.1.tgz", - "integrity": "sha512-lID/vxSuKWXM55XhAKNoYXu9Cutoq5hFdkbTdI/zDKQktXzcWBVhNsOkiZFTMU9UtEWuGRNe0HUgmsFldIdxVA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.6.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, + "node_modules/@esbuild/linux-arm": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.0.tgz", + "integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" + "node": ">=18" } }, - "node_modules/@opentelemetry/sdk-logs": { - "version": "0.214.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.214.0.tgz", - "integrity": "sha512-zf6acnScjhsaBUU22zXZ/sLWim1dfhUAbGXdMmHmNG3LfBnQ3DKsOCITb2IZwoUsNNMTogqFKBnlIPPftUgGwA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.214.0", - "@opentelemetry/core": "2.6.1", - "@opentelemetry/resources": "2.6.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.0.tgz", + "integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.4.0 <1.10.0" + "node": ">=18" } }, - "node_modules/@opentelemetry/sdk-metrics": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.6.1.tgz", - "integrity": "sha512-9t9hJHX15meBy2NmTJxL+NJfXmnausR2xUDvE19XQce0Qi/GBtDGamU8nS1RMbdgDmhgpm3VaOu2+fiS/SfTpQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.6.1", - "@opentelemetry/resources": "2.6.1" - }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.0.tgz", + "integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.9.0 <1.10.0" + "node": ">=18" } }, - "node_modules/@opentelemetry/sdk-trace-base": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.6.1.tgz", - "integrity": "sha512-r86ut4T1e8vNwB35CqCcKd45yzqH6/6Wzvpk2/cZB8PsPLlZFTvrh8yfOS3CYZYcUmAx4hHTZJ8AO8Dj8nrdhw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.6.1", - "@opentelemetry/resources": "2.6.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.0.tgz", + "integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" + "node": ">=18" } }, - "node_modules/@opentelemetry/sdk-trace-node": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-node/-/sdk-trace-node-2.6.1.tgz", - "integrity": "sha512-Hh2i4FwHWRFhnO2Q/p6svMxy8MPsNCG0uuzUY3glqm0rwM0nQvbTO1dXSp9OqQoTKXcQzaz9q1f65fsurmOhNw==", - "license": "Apache-2.0", + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.0.tgz", + "integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.0.tgz", + "integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.0.tgz", + "integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.0.tgz", + "integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.0.tgz", + "integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.0.tgz", + "integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.0.tgz", + "integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.0.tgz", + "integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.0.tgz", + "integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.0.tgz", + "integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.0.tgz", + "integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.0.tgz", + "integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.0.tgz", + "integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.0.tgz", + "integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@exodus/schemasafe": { + "version": "1.3.0", + "license": "MIT" + }, + "node_modules/@faker-js/faker": { + "version": "7.6.0", + "license": "MIT", + "engines": { + "node": ">=14.0.0", + "npm": ">=6.0.0" + } + }, + "node_modules/@fastify/ajv-compiler": { + "version": "4.0.5", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "ajv": "^8.12.0", + "ajv-formats": "^3.0.1", + "fast-uri": "^3.0.0" + } + }, + "node_modules/@fastify/cors": { + "version": "11.2.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", "dependencies": { - "@opentelemetry/context-async-hooks": "2.6.1", - "@opentelemetry/core": "2.6.1", - "@opentelemetry/sdk-trace-base": "2.6.1" + "fastify-plugin": "^5.0.0", + "toad-cache": "^3.7.0" + } + }, + "node_modules/@fastify/cors/node_modules/fastify-plugin": { + "version": "5.1.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, + "node_modules/@fastify/error": { + "version": "4.2.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, + "node_modules/@fastify/fast-json-stringify-compiler": { + "version": "5.0.3", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "fast-json-stringify": "^6.0.0" + } + }, + "node_modules/@fastify/formbody": { + "version": "8.0.2", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "fast-querystring": "^1.1.2", + "fastify-plugin": "^5.0.0" + } + }, + "node_modules/@fastify/formbody/node_modules/fastify-plugin": { + "version": "5.1.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, + "node_modules/@fastify/forwarded": { + "version": "3.0.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, + "node_modules/@fastify/merge-json-schemas": { + "version": "0.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/@fastify/proxy-addr": { + "version": "5.1.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "@fastify/forwarded": "^3.0.0", + "ipaddr.js": "^2.1.0" + } + }, + "node_modules/@fastify/proxy-addr/node_modules/ipaddr.js": { + "version": "2.4.0", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/@humanwhocodes/momoa": { + "version": "2.0.4", + "license": "Apache-2.0", + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@jsdevtools/ono": { + "version": "7.1.3", + "license": "MIT" + }, + "node_modules/@jsep-plugin/assignment": { + "version": "1.3.0", + "license": "MIT", + "engines": { + "node": ">= 10.16.0" }, + "peerDependencies": { + "jsep": "^0.4.0||^1.0.0" + } + }, + "node_modules/@jsep-plugin/regex": { + "version": "1.0.4", + "license": "MIT", "engines": { - "node": "^18.19.0 || >=20.6.0" + "node": ">= 10.16.0" }, "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" + "jsep": "^0.4.0||^1.0.0" } }, - "node_modules/@opentelemetry/semantic-conventions": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.40.0.tgz", - "integrity": "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw==", - "license": "Apache-2.0", + "node_modules/@jsep-plugin/ternary": { + "version": "1.1.4", + "license": "MIT", "engines": { - "node": ">=14" + "node": ">= 10.16.0" + }, + "peerDependencies": { + "jsep": "^0.4.0||^1.0.0" } }, - "node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", - "license": "BSD-3-Clause" + "node_modules/@lukeed/csprng": { + "version": "1.1.0", + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "node_modules/@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", - "license": "BSD-3-Clause" + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.5.tgz", + "integrity": "sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } }, - "node_modules/@protobufjs/codegen": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.5.tgz", - "integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==", - "license": "BSD-3-Clause" + "node_modules/@nestjs/common": { + "version": "11.1.26", + "license": "MIT", + "dependencies": { + "file-type": "21.3.4", + "iterare": "1.2.1", + "load-esm": "1.0.3", + "tslib": "2.8.1", + "uid": "2.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nest" + }, + "peerDependencies": { + "class-transformer": ">=0.4.1", + "class-validator": ">=0.13.2", + "reflect-metadata": "^0.1.12 || ^0.2.0", + "rxjs": "^7.1.0" + }, + "peerDependenciesMeta": { + "class-transformer": { + "optional": true + }, + "class-validator": { + "optional": true + } + } }, - "node_modules/@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", - "license": "BSD-3-Clause" + "node_modules/@nestjs/common/node_modules/file-type": { + "version": "21.3.4", + "license": "MIT", + "dependencies": { + "@tokenizer/inflate": "^0.4.1", + "strtok3": "^10.3.4", + "token-types": "^6.1.1", + "uint8array-extras": "^1.4.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sindresorhus/file-type?sponsor=1" + } }, - "node_modules/@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", - "license": "BSD-3-Clause", + "node_modules/@nestjs/core": { + "version": "11.1.26", + "license": "MIT", "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" + "fast-safe-stringify": "2.1.1", + "iterare": "1.2.1", + "path-to-regexp": "8.4.2", + "tslib": "2.8.1", + "uid": "2.0.2" + }, + "engines": { + "node": ">= 20" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nest" + }, + "peerDependencies": { + "@nestjs/common": "^11.0.0", + "@nestjs/microservices": "^11.0.0", + "@nestjs/platform-express": "^11.0.0", + "@nestjs/websockets": "^11.0.0", + "reflect-metadata": "^0.1.12 || ^0.2.0", + "rxjs": "^7.1.0" + }, + "peerDependenciesMeta": { + "@nestjs/microservices": { + "optional": true + }, + "@nestjs/platform-express": { + "optional": true + }, + "@nestjs/websockets": { + "optional": true + } } }, - "node_modules/@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", - "license": "BSD-3-Clause" + "node_modules/@nestjs/platform-fastify": { + "version": "11.1.26", + "license": "MIT", + "dependencies": { + "@fastify/cors": "11.2.0", + "@fastify/formbody": "8.0.2", + "fast-querystring": "1.1.2", + "fastify": "5.8.5", + "fastify-plugin": "5.1.0", + "find-my-way": "9.6.0", + "light-my-request": "6.6.0", + "path-to-regexp": "8.4.2", + "reusify": "1.1.0", + "tslib": "2.8.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nest" + }, + "peerDependencies": { + "@fastify/static": "^8.0.0 || ^9.0.0", + "@fastify/view": "^10.0.0 || ^11.0.0", + "@nestjs/common": "^11.0.0", + "@nestjs/core": "^11.0.0" + }, + "peerDependenciesMeta": { + "@fastify/static": { + "optional": true + }, + "@fastify/view": { + "optional": true + } + } }, - "node_modules/@protobufjs/inquire": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.1.tgz", - "integrity": "sha512-mnzgDV26ueAvk7rsbt9L7bE0SuAoqyuys/sMMrmVcN5x9VsxpcG3rqAUSgDyLp0UZlmNfIbQ4fHfCtreVBk8Ew==", - "license": "BSD-3-Clause" + "node_modules/@nestjs/platform-fastify/node_modules/fastify-plugin": { + "version": "5.1.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" }, - "node_modules/@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", - "license": "BSD-3-Clause" + "node_modules/@noble/hashes": { + "version": "1.8.0", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } }, - "node_modules/@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", - "license": "BSD-3-Clause" + "node_modules/@nodable/entities": { + "version": "2.1.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/nodable" + } + ], + "license": "MIT" }, - "node_modules/@protobufjs/utf8": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.1.tgz", - "integrity": "sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==", - "license": "BSD-3-Clause" + "node_modules/@oxc-project/types": { + "version": "0.133.0", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@pinojs/redact": { + "version": "0.4.0", + "license": "MIT" }, "node_modules/@redocly/ajv": { "version": "8.18.3", - "resolved": "https://registry.npmjs.org/@redocly/ajv/-/ajv-8.18.3.tgz", - "integrity": "sha512-l42u0of3hY98sN2A+M4qTX1O/KrpgGH32Hu9kP2GtHyD5Dfqq86PKFLe5dwaD8DEnNmlOlll2BAmeEtf0DaySg==", "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -680,275 +1215,405 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@redocly/cli": { - "version": "2.30.3", - "resolved": "https://registry.npmjs.org/@redocly/cli/-/cli-2.30.3.tgz", - "integrity": "sha512-z2T4+v4qwyEl1Cb2bRS77sK3jiYDOnIVZUYF8/3OWA1N+4znGIvs85xm5pAqQE0kltoIJuisekqERMvhdG6Z4w==", + "node_modules/@redocly/config": { + "version": "0.49.0", + "license": "MIT", + "dependencies": { + "json-schema-to-ts": "2.7.2" + } + }, + "node_modules/@redocly/openapi-core": { + "version": "2.32.0", "license": "MIT", "dependencies": { - "@opentelemetry/exporter-trace-otlp-http": "0.214.0", - "@opentelemetry/resources": "2.6.1", - "@opentelemetry/sdk-trace-node": "2.6.1", - "@opentelemetry/semantic-conventions": "1.40.0", - "@redocly/cli-otel": "0.1.2", - "@redocly/openapi-core": "2.30.3", - "@redocly/respect-core": "2.30.3", + "@redocly/ajv": "^8.18.1", + "@redocly/config": "^0.49.0", "ajv": "npm:@redocly/ajv@8.18.1", "ajv-formats": "^3.0.1", "colorette": "^1.2.0", - "cookie": "^0.7.2", - "dotenv": "16.4.7", - "glob": "^13.0.5", - "handlebars": "^4.7.9", - "https-proxy-agent": "^7.0.5", - "mobx": "^6.0.4", + "js-levenshtein": "^1.1.6", + "js-yaml": "^4.1.0", "picomatch": "^4.0.4", "pluralize": "^8.0.0", - "react": "^17.0.0 || ^18.2.0 || ^19.2.1", - "react-dom": "^17.0.0 || ^18.2.0 || ^19.2.1", - "redoc": "2.5.1", - "semver": "^7.5.2", - "set-cookie-parser": "^2.3.5", - "simple-websocket": "^9.0.0", - "styled-components": "6.3.9", - "ulid": "^3.0.1", - "undici": "6.24.0", - "yargs": "17.0.1" + "yaml-ast-parser": "0.0.43" }, - "bin": { - "openapi": "bin/cli.js", - "redocly": "bin/cli.js" + "engines": { + "node": ">=22.12.0 || >=20.19.0 <21.0.0", + "npm": ">=10" + } + }, + "node_modules/@redocly/openapi-core/node_modules/ajv": { + "name": "@redocly/ajv", + "version": "8.18.1", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@redocly/openapi-core/node_modules/colorette": { + "version": "1.4.0", + "license": "MIT" + }, + "node_modules/@redocly/respect-core": { + "version": "2.32.0", + "license": "MIT", + "dependencies": { + "@faker-js/faker": "^7.6.0", + "@noble/hashes": "^1.8.0", + "@redocly/ajv": "^8.18.1", + "@redocly/openapi-core": "2.32.0", + "ajv": "npm:@redocly/ajv@8.18.1", + "better-ajv-errors": "^2.0.3", + "colorette": "^2.0.20", + "json-pointer": "^0.6.2", + "jsonpath-rfc9535": "1.3.0", + "openapi-sampler": "^1.7.1", + "outdent": "^0.8.0", + "picomatch": "^4.0.4" }, "engines": { "node": ">=22.12.0 || >=20.19.0 <21.0.0", "npm": ">=10" } }, - "node_modules/@redocly/cli-otel": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@redocly/cli-otel/-/cli-otel-0.1.2.tgz", - "integrity": "sha512-Bg7BoO5t1x3lVK+KhA5aGPmeXpQmdf6WtTYHhelKJCsQ+tRMiJoFAQoKHoBHAoNxXrhlS3K9lKFLHGmtxsFQfA==", + "node_modules/@redocly/respect-core/node_modules/ajv": { + "name": "@redocly/ajv", + "version": "8.18.1", "license": "MIT", "dependencies": { - "ulid": "^2.3.0" + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@redocly/cli-otel/node_modules/ulid": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/ulid/-/ulid-2.4.0.tgz", - "integrity": "sha512-fIRiVTJNcSRmXKPZtGzFQv9WRrZ3M9eoptl/teFJvjOzmpU+/K/JH6HZ8deBfb5vMEpicJcLn7JmvdknlMq7Zg==", + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz", + "integrity": "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "bin": { - "ulid": "bin/cli.js" + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.3", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.3.tgz", + "integrity": "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.3.tgz", + "integrity": "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@redocly/cli/node_modules/ajv": { - "name": "@redocly/ajv", - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@redocly/ajv/-/ajv-8.18.1.tgz", - "integrity": "sha512-Ifm/pP/tul1qmAecpbVxCBluVE32rKfjf8gYXH4xI2gCv9mRWFhJMHzkPDM4TXlxwPQYIFegymlsy8lXz7optA==", + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.3.tgz", + "integrity": "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==", + "cpu": [ + "arm" + ], + "dev": true, "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@redocly/cli/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.3.tgz", + "integrity": "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@redocly/cli/node_modules/dotenv": { - "version": "16.4.7", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", - "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", - "license": "BSD-2-Clause", + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.3.tgz", + "integrity": "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@redocly/cli/node_modules/yargs": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.0.1.tgz", - "integrity": "sha512-xBBulfCc8Y6gLFcrPvtqKz9hz8SO0l1Ni8GgDekvBX2ro0HRQImDGnikfc33cgzcYUSncapnNcZDjVFIH3f6KQ==", + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.3.tgz", + "integrity": "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=12" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@redocly/cli/node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "license": "ISC", + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.3.tgz", + "integrity": "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=10" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@redocly/config": { - "version": "0.48.1", - "resolved": "https://registry.npmjs.org/@redocly/config/-/config-0.48.1.tgz", - "integrity": "sha512-vq8GM3e0KiglqkwE5Lb9XayrmZY4dHCs21BsvV92yAZN68f1N9cZUuwY1SwnztPbH06dn9uLzubBl/JNfImqfA==", + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz", + "integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", - "dependencies": { - "json-schema-to-ts": "2.7.2" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@redocly/openapi-core": { - "version": "2.30.3", - "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-2.30.3.tgz", - "integrity": "sha512-roSwxkitl+JY3LajLEg6n9ujaFkCB4cqtjgrjXxedgk57Qde5t0Vn4HBYkOomw1bHOI7W+Ux2qfPQOpzK7BnLg==", + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz", + "integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], "license": "MIT", - "dependencies": { - "@redocly/ajv": "^8.18.1", - "@redocly/config": "^0.48.1", - "ajv": "npm:@redocly/ajv@8.18.1", - "ajv-formats": "^3.0.1", - "colorette": "^1.2.0", - "js-levenshtein": "^1.1.6", - "js-yaml": "^4.1.0", - "picomatch": "^4.0.4", - "pluralize": "^8.0.0", - "yaml-ast-parser": "0.0.43" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=22.12.0 || >=20.19.0 <21.0.0", - "npm": ">=10" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@redocly/openapi-core/node_modules/ajv": { - "name": "@redocly/ajv", - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@redocly/ajv/-/ajv-8.18.1.tgz", - "integrity": "sha512-Ifm/pP/tul1qmAecpbVxCBluVE32rKfjf8gYXH4xI2gCv9mRWFhJMHzkPDM4TXlxwPQYIFegymlsy8lXz7optA==", + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.3.tgz", + "integrity": "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@redocly/respect-core": { - "version": "2.30.3", - "resolved": "https://registry.npmjs.org/@redocly/respect-core/-/respect-core-2.30.3.tgz", - "integrity": "sha512-9bEETk86ECE6n/0g/6MEQ3RryamTOv6mdZ0WDmHUmO3PfVUzHKFRgNcFnvyTWEC2nApdO9GbnYLjZcwyPwUdOw==", + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.3.tgz", + "integrity": "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==", + "cpu": [ + "wasm32" + ], + "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@faker-js/faker": "^7.6.0", - "@noble/hashes": "^1.8.0", - "@redocly/ajv": "^8.18.1", - "@redocly/openapi-core": "2.30.3", - "ajv": "npm:@redocly/ajv@8.18.1", - "better-ajv-errors": "^2.0.3", - "colorette": "^2.0.20", - "json-pointer": "^0.6.2", - "jsonpath-rfc9535": "1.3.0", - "openapi-sampler": "^1.7.1", - "outdent": "^0.8.0", - "picomatch": "^4.0.4" + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" }, "engines": { - "node": ">=22.12.0 || >=20.19.0 <21.0.0", - "npm": ">=10" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@redocly/respect-core/node_modules/@faker-js/faker": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-7.6.0.tgz", - "integrity": "sha512-XK6BTq1NDMo9Xqw/YkYyGjSsg44fbNwYRx7QK2CuoQgyy+f1rrTDHoExVM5PsyXCtfl2vs2vVJ0MN0yN6LppRw==", + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.3.tgz", + "integrity": "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=14.0.0", - "npm": ">=6.0.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@redocly/respect-core/node_modules/ajv": { - "name": "@redocly/ajv", - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@redocly/ajv/-/ajv-8.18.1.tgz", - "integrity": "sha512-Ifm/pP/tul1qmAecpbVxCBluVE32rKfjf8gYXH4xI2gCv9mRWFhJMHzkPDM4TXlxwPQYIFegymlsy8lXz7optA==", + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.3.tgz", + "integrity": "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==", + "cpu": [ + "x64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@redocly/respect-core/node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "dev": true, "license": "MIT" }, "node_modules/@scalar/openapi-types": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@scalar/openapi-types/-/openapi-types-0.8.0.tgz", - "integrity": "sha512-WmaxVSfvY5K/TwcG2B2TU1WOe1As1uc2s7myswtP6dBlcjU3hM08SApxv/jmyGaCE8t4gO5BBhmHY4pDUfmr2g==", + "version": "0.9.1", "license": "MIT", "engines": { "node": ">=22" } }, "node_modules/@scalar/openapi-upgrader": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/@scalar/openapi-upgrader/-/openapi-upgrader-0.2.7.tgz", - "integrity": "sha512-sC/uLQOivfX+Oef2QhUpgmERL7KZc1z+hiYkcwZQaUyVOHh5e6OscW0skfzbxKPyJfQ6Ocv0Iom9wMToCGaAPw==", + "version": "0.2.9", "license": "MIT", "dependencies": { - "@scalar/openapi-types": "0.8.0" + "@scalar/openapi-types": "0.9.1" }, "engines": { "node": ">=22" } }, - "node_modules/@so-ric/colorspace": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@so-ric/colorspace/-/colorspace-1.1.6.tgz", - "integrity": "sha512-/KiKkpHNOBgkFJwu9sh48LkHSMYGyuTcSFK/qMBdnOAlrRJzRSXAOFB5qwzaVQuDl8wAvHVMkaASQDReTahxuw==", - "license": "MIT", + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@stoplight/better-ajv-errors": { + "version": "1.0.3", + "license": "Apache-2.0", "dependencies": { - "color": "^5.0.2", - "text-hex": "1.0.x" + "jsonpointer": "^5.0.0", + "leven": "^3.1.0" + }, + "engines": { + "node": "^12.20 || >= 14.13" + }, + "peerDependencies": { + "ajv": ">=8" } }, "node_modules/@stoplight/json": { "version": "3.21.7", - "resolved": "https://registry.npmjs.org/@stoplight/json/-/json-3.21.7.tgz", - "integrity": "sha512-xcJXgKFqv/uCEgtGlPxy3tPA+4I+ZI4vAuMJ885+ThkTHFVkC+0Fm58lA9NlsyjnkpxFh4YiQWpH+KefHdbA0A==", "license": "Apache-2.0", "dependencies": { "@stoplight/ordered-object-literal": "^1.0.3", @@ -964,8 +1629,6 @@ }, "node_modules/@stoplight/json-ref-readers": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@stoplight/json-ref-readers/-/json-ref-readers-1.2.2.tgz", - "integrity": "sha512-nty0tHUq2f1IKuFYsLM4CXLZGHdMn+X/IwEUIpeSOXt0QjMUbL0Em57iJUDzz+2MkWG83smIigNZ3fauGjqgdQ==", "license": "Apache-2.0", "dependencies": { "node-fetch": "^2.6.0", @@ -975,10 +1638,12 @@ "node": ">=8.3.0" } }, + "node_modules/@stoplight/json-ref-readers/node_modules/tslib": { + "version": "1.14.1", + "license": "0BSD" + }, "node_modules/@stoplight/json-ref-resolver": { "version": "3.1.6", - "resolved": "https://registry.npmjs.org/@stoplight/json-ref-resolver/-/json-ref-resolver-3.1.6.tgz", - "integrity": "sha512-YNcWv3R3n3U6iQYBsFOiWSuRGE5su1tJSiX6pAPRVk7dP0L7lqCteXGzuVRQ0gMZqUl8v1P0+fAKxF6PLo9B5A==", "license": "Apache-2.0", "dependencies": { "@stoplight/json": "^3.21.0", @@ -996,22 +1661,12 @@ "node": ">=8.3.0" } }, - "node_modules/@stoplight/json-ref-resolver/node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, "node_modules/@stoplight/json/node_modules/safe-stable-stringify": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-1.1.1.tgz", - "integrity": "sha512-ERq4hUjKDbJfE4+XtZLFPCDi8Vb1JqaxAPTxWFLBx8XcAlf9Bda/ZJdVezs/NAfsMQScyIlUMx+Yeu7P7rx5jw==", "license": "MIT" }, "node_modules/@stoplight/ordered-object-literal": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@stoplight/ordered-object-literal/-/ordered-object-literal-1.0.5.tgz", - "integrity": "sha512-COTiuCU5bgMUtbIFBuyyh2/yVVzlr5Om0v5utQDgBCuQUOPgU1DwoffkTfg4UBQOvByi5foF4w4T+H9CoRe5wg==", "license": "Apache-2.0", "engines": { "node": ">=8" @@ -1019,17 +1674,13 @@ }, "node_modules/@stoplight/path": { "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@stoplight/path/-/path-1.3.2.tgz", - "integrity": "sha512-lyIc6JUlUA8Ve5ELywPC8I2Sdnh1zc1zmbYgVarhXIp9YeAB0ReeqmGEOWNtlHkbP2DAA1AL65Wfn2ncjK/jtQ==", "license": "Apache-2.0", "engines": { "node": ">=8" } }, "node_modules/@stoplight/spectral-core": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-core/-/spectral-core-1.22.0.tgz", - "integrity": "sha512-4hTxMDs4TFUG4/jKjaZttA65gNuV2PCKI9+51I+J4nL6ylo17DlbW+sl6byKnBuV/85HxaV33ri5fEGlp8lTSA==", + "version": "1.23.0", "license": "Apache-2.0", "dependencies": { "@stoplight/better-ajv-errors": "1.0.3", @@ -1058,48 +1709,8 @@ "node": "^16.20 || ^18.18 || >= 20.17" } }, - "node_modules/@stoplight/spectral-core/node_modules/@stoplight/better-ajv-errors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@stoplight/better-ajv-errors/-/better-ajv-errors-1.0.3.tgz", - "integrity": "sha512-0p9uXkuB22qGdNfy3VeEhxkU5uwvp/KrBTAbrLBURv6ilxIVwanKwjMc41lQfIVgPGcOkmLbTolfFrSsueu7zA==", - "license": "Apache-2.0", - "dependencies": { - "jsonpointer": "^5.0.0", - "leven": "^3.1.0" - }, - "engines": { - "node": "^12.20 || >= 14.13" - }, - "peerDependencies": { - "ajv": ">=8" - } - }, - "node_modules/@stoplight/spectral-core/node_modules/@stoplight/types": { - "version": "13.6.0", - "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-13.6.0.tgz", - "integrity": "sha512-dzyuzvUjv3m1wmhPfq82lCVYGcXG0xUYgqnWfCq3PCVR4BKFhjdkHrnJ+jIDoMKvXb05AZP/ObQF6+NpDo29IQ==", - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.4", - "utility-types": "^3.10.0" - }, - "engines": { - "node": "^12.20 || >=14.13" - } - }, - "node_modules/@stoplight/spectral-core/node_modules/ajv-errors": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-3.0.0.tgz", - "integrity": "sha512-V3wD15YHfHz6y0KdhYFjyy9vWtEVALT9UrxfN3zqlI6dMioHnJrqOYfyPKol3oqrnCM9uwkcdCwkJ0WUcbLMTQ==", - "license": "MIT", - "peerDependencies": { - "ajv": "^8.0.1" - } - }, "node_modules/@stoplight/spectral-core/node_modules/ajv-formats": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", "license": "MIT", "dependencies": { "ajv": "^8.0.0" @@ -1113,26 +1724,12 @@ } } }, - "node_modules/@stoplight/spectral-core/node_modules/lodash": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", - "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", - "license": "MIT" - }, - "node_modules/@stoplight/spectral-core/node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, "node_modules/@stoplight/spectral-formats": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-formats/-/spectral-formats-1.8.2.tgz", - "integrity": "sha512-c06HB+rOKfe7tuxg0IdKDEA5XnjL2vrn/m/OVIIxtINtBzphZrOgtRn7epQ5bQF5SWp84Ue7UJWaGgDwVngMFw==", + "version": "1.8.3", "license": "Apache-2.0", "dependencies": { "@stoplight/json": "^3.17.0", - "@stoplight/spectral-core": "^1.19.2", + "@stoplight/spectral-core": "1.23.0", "@types/json-schema": "^7.0.7", "tslib": "^2.8.1" }, @@ -1140,63 +1737,28 @@ "node": "^16.20 || ^18.18 || >= 20.17" } }, - "node_modules/@stoplight/spectral-formats/node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, "node_modules/@stoplight/spectral-functions": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-functions/-/spectral-functions-1.10.1.tgz", - "integrity": "sha512-obu8ZfoHxELOapfGsCJixKZXZcffjg+lSoNuttpmUFuDzVLT3VmH8QkPXfOGOL5Pz80BR35ClNAToDkdnYIURg==", + "version": "1.10.3", "license": "Apache-2.0", "dependencies": { "@stoplight/better-ajv-errors": "1.0.3", "@stoplight/json": "^3.17.1", - "@stoplight/spectral-core": "^1.19.4", + "@stoplight/spectral-core": "1.23.0", "@stoplight/spectral-formats": "^1.8.1", "@stoplight/spectral-runtime": "^1.1.2", - "ajv": "^8.17.1", + "ajv": "^8.18.0", "ajv-draft-04": "~1.0.0", "ajv-errors": "~3.0.0", "ajv-formats": "~2.1.1", - "lodash": "~4.17.21", + "lodash": "^4.18.1", "tslib": "^2.8.1" }, "engines": { "node": "^16.20 || ^18.18 || >= 20.17" } }, - "node_modules/@stoplight/spectral-functions/node_modules/@stoplight/better-ajv-errors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@stoplight/better-ajv-errors/-/better-ajv-errors-1.0.3.tgz", - "integrity": "sha512-0p9uXkuB22qGdNfy3VeEhxkU5uwvp/KrBTAbrLBURv6ilxIVwanKwjMc41lQfIVgPGcOkmLbTolfFrSsueu7zA==", - "license": "Apache-2.0", - "dependencies": { - "jsonpointer": "^5.0.0", - "leven": "^3.1.0" - }, - "engines": { - "node": "^12.20 || >= 14.13" - }, - "peerDependencies": { - "ajv": ">=8" - } - }, - "node_modules/@stoplight/spectral-functions/node_modules/ajv-errors": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-3.0.0.tgz", - "integrity": "sha512-V3wD15YHfHz6y0KdhYFjyy9vWtEVALT9UrxfN3zqlI6dMioHnJrqOYfyPKol3oqrnCM9uwkcdCwkJ0WUcbLMTQ==", - "license": "MIT", - "peerDependencies": { - "ajv": "^8.0.1" - } - }, "node_modules/@stoplight/spectral-functions/node_modules/ajv-formats": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", "license": "MIT", "dependencies": { "ajv": "^8.0.0" @@ -1210,16 +1772,8 @@ } } }, - "node_modules/@stoplight/spectral-functions/node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, "node_modules/@stoplight/spectral-parsers": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-parsers/-/spectral-parsers-1.0.5.tgz", - "integrity": "sha512-ANDTp2IHWGvsQDAY85/jQi9ZrF4mRrA5bciNHX+PUxPr4DwS6iv4h+FVWJMVwcEYdpyoIdyL+SRmHdJfQEPmwQ==", "license": "Apache-2.0", "dependencies": { "@stoplight/json": "~3.21.0", @@ -1233,8 +1787,6 @@ }, "node_modules/@stoplight/spectral-parsers/node_modules/@stoplight/types": { "version": "14.1.1", - "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-14.1.1.tgz", - "integrity": "sha512-/kjtr+0t0tjKr+heVfviO9FrU/uGLc+QNX3fHJc19xsCNYqU7lVhaXxDmEID9BZTjG+/r9pK9xP/xU02XGg65g==", "license": "Apache-2.0", "dependencies": { "@types/json-schema": "^7.0.4", @@ -1244,16 +1796,8 @@ "node": "^12.20 || >=14.13" } }, - "node_modules/@stoplight/spectral-parsers/node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, "node_modules/@stoplight/spectral-ref-resolver": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-ref-resolver/-/spectral-ref-resolver-1.0.5.tgz", - "integrity": "sha512-gj3TieX5a9zMW29z3mBlAtDOCgN3GEc1VgZnCVlr5irmR4Qi5LuECuFItAq4pTn5Zu+sW5bqutsCH7D4PkpyAA==", "license": "Apache-2.0", "dependencies": { "@stoplight/json-ref-readers": "1.2.2", @@ -1266,22 +1810,14 @@ "node": "^16.20 || ^18.18 || >= 20.17" } }, - "node_modules/@stoplight/spectral-ref-resolver/node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, "node_modules/@stoplight/spectral-rulesets": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-rulesets/-/spectral-rulesets-1.22.1.tgz", - "integrity": "sha512-DaaQJioKuYkRsOuKIJfX2ek7G7f6OCU3CI3K7ABaOcTFMiHj29SJLDdb04mCjXZFXMlXHjmCl2ZpKW6heieXpw==", + "version": "1.22.4", "license": "Apache-2.0", "dependencies": { "@asyncapi/specs": "^6.8.0", "@stoplight/better-ajv-errors": "1.0.3", "@stoplight/json": "^3.17.0", - "@stoplight/spectral-core": "^1.19.4", + "@stoplight/spectral-core": "1.23.0", "@stoplight/spectral-formats": "^1.8.1", "@stoplight/spectral-functions": "^1.9.1", "@stoplight/spectral-runtime": "^1.1.2", @@ -1298,26 +1834,8 @@ "node": "^16.20 || ^18.18 || >= 20.17" } }, - "node_modules/@stoplight/spectral-rulesets/node_modules/@stoplight/better-ajv-errors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@stoplight/better-ajv-errors/-/better-ajv-errors-1.0.3.tgz", - "integrity": "sha512-0p9uXkuB22qGdNfy3VeEhxkU5uwvp/KrBTAbrLBURv6ilxIVwanKwjMc41lQfIVgPGcOkmLbTolfFrSsueu7zA==", - "license": "Apache-2.0", - "dependencies": { - "jsonpointer": "^5.0.0", - "leven": "^3.1.0" - }, - "engines": { - "node": "^12.20 || >= 14.13" - }, - "peerDependencies": { - "ajv": ">=8" - } - }, "node_modules/@stoplight/spectral-rulesets/node_modules/ajv-formats": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", "license": "MIT", "dependencies": { "ajv": "^8.0.0" @@ -1331,22 +1849,8 @@ } } }, - "node_modules/@stoplight/spectral-rulesets/node_modules/lodash": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", - "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", - "license": "MIT" - }, - "node_modules/@stoplight/spectral-rulesets/node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, "node_modules/@stoplight/spectral-runtime": { "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-runtime/-/spectral-runtime-1.1.5.tgz", - "integrity": "sha512-6/HSCQBKnI4M5qonCKos2W7oggXv+U/ml+m/cAd4eJAYfIVEmaLUo03qSWIIl4cBc5ujJPmn2WnCiRrz1++P7Q==", "license": "Apache-2.0", "dependencies": { "@stoplight/json": "^3.20.1", @@ -1361,22 +1865,8 @@ "node": "^16.20 || ^18.18 || >= 20.17" } }, - "node_modules/@stoplight/spectral-runtime/node_modules/lodash": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", - "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", - "license": "MIT" - }, - "node_modules/@stoplight/spectral-runtime/node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, "node_modules/@stoplight/types": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-13.20.0.tgz", - "integrity": "sha512-2FNTv05If7ib79VPDA/r9eUet76jewXFH2y2K5vuge6SXbRHtWBhcaRmu+6QpF4/WRNoJj5XYRSwLGXDxysBGA==", + "version": "13.6.0", "license": "Apache-2.0", "dependencies": { "@types/json-schema": "^7.0.4", @@ -1388,8 +1878,6 @@ }, "node_modules/@stoplight/yaml": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@stoplight/yaml/-/yaml-4.3.0.tgz", - "integrity": "sha512-JZlVFE6/dYpP9tQmV0/ADfn32L9uFarHWxfcRhReKUnljz1ZiUM5zpX+PH8h5CJs6lao3TuFqnPm9IJJCEkE2w==", "license": "Apache-2.0", "dependencies": { "@stoplight/ordered-object-literal": "^1.0.5", @@ -1403,14 +1891,10 @@ }, "node_modules/@stoplight/yaml-ast-parser": { "version": "0.0.50", - "resolved": "https://registry.npmjs.org/@stoplight/yaml-ast-parser/-/yaml-ast-parser-0.0.50.tgz", - "integrity": "sha512-Pb6M8TDO9DtSVla9yXSTAxmo9GVEouq5P40DWXdOie69bXogZTkgvopCq+yEvTMA0F6PEvdJmbtTV3ccIp11VQ==", "license": "Apache-2.0" }, "node_modules/@stoplight/yaml/node_modules/@stoplight/types": { "version": "14.1.1", - "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-14.1.1.tgz", - "integrity": "sha512-/kjtr+0t0tjKr+heVfviO9FrU/uGLc+QNX3fHJc19xsCNYqU7lVhaXxDmEID9BZTjG+/r9pK9xP/xU02XGg65g==", "license": "Apache-2.0", "dependencies": { "@types/json-schema": "^7.0.4", @@ -1420,187 +1904,192 @@ "node": "^12.20 || >=14.13" } }, - "node_modules/@stoplight/yaml/node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, - "node_modules/@types/body-parser": { - "version": "1.19.6", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", - "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "node_modules/@tokenizer/inflate": { + "version": "0.4.1", "license": "MIT", "dependencies": { - "@types/connect": "*", - "@types/node": "*" + "debug": "^4.4.3", + "token-types": "^6.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" } }, - "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } + "node_modules/@tokenizer/token": { + "version": "0.3.0", + "license": "MIT" }, - "node_modules/@types/es-aggregate-error": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/es-aggregate-error/-/es-aggregate-error-1.0.6.tgz", - "integrity": "sha512-qJ7LIFp06h1QE1aVxbVd+zJP2wdaugYXYfd6JxsyRMrYHaxb6itXPogW2tz+ylUJ1n1b+JF1PHyYCfYHm0dvUg==", + "node_modules/@tybys/wasm-util": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", + "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", + "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@types/node": "*" + "tslib": "^2.4.0" } }, - "node_modules/@types/express": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.6.tgz", - "integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==", + "node_modules/@types/chai": { + "version": "5.2.3", + "dev": true, "license": "MIT", "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^5.0.0", - "@types/serve-static": "^2" + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" } }, - "node_modules/@types/express-serve-static-core": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.1.tgz", - "integrity": "sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==", + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/es-aggregate-error": { + "version": "1.0.6", "license": "MIT", "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" + "@types/node": "*" } }, - "node_modules/@types/http-errors": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", - "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "node_modules/@types/estree": { + "version": "1.0.9", + "dev": true, "license": "MIT" }, "node_modules/@types/json-schema": { "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "license": "MIT" }, - "node_modules/@types/multer": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/multer/-/multer-2.1.0.tgz", - "integrity": "sha512-zYZb0+nJhOHtPpGDb3vqPjwpdeGlGC157VpkqNQL+UU2qwoacoQ7MpsAmUptI/0Oa127X32JzWDqQVEXp2RcIA==", - "license": "MIT", - "dependencies": { - "@types/express": "*" - } - }, "node_modules/@types/node": { - "version": "24.10.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.0.tgz", - "integrity": "sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==", + "version": "25.9.2", "license": "MIT", "dependencies": { - "undici-types": "~7.16.0" + "undici-types": ">=7.24.0 <7.24.7" } }, - "node_modules/@types/qs": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.0.tgz", - "integrity": "sha512-JawvT8iBVWpzTrz3EGw9BTQFg3BQNmwERdKE22vlTxawwtbyUSlMppvZYKLZzB5zgACXdXxbD3m1bXaMqP/9ow==", - "license": "MIT" - }, - "node_modules/@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "node_modules/@types/urijs": { + "version": "1.19.26", "license": "MIT" }, - "node_modules/@types/send": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", - "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", + "node_modules/@vitest/expect": { + "version": "4.1.8", + "dev": true, "license": "MIT", "dependencies": { - "@types/node": "*" + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.8", + "@vitest/utils": "4.1.8", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/@types/serve-static": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-2.2.0.tgz", - "integrity": "sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==", + "node_modules/@vitest/mocker": { + "version": "4.1.8", + "dev": true, "license": "MIT", "dependencies": { - "@types/http-errors": "*", - "@types/node": "*" + "@vitest/spy": "4.1.8", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } } }, - "node_modules/@types/stylis": { - "version": "4.2.7", - "resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.7.tgz", - "integrity": "sha512-VgDNokpBoKF+wrdvhAAfS55OMQpL6QRglwTwNC3kIgBrzZxA4WsFj+2eLfEA/uMUDzBcEhYmjSbwQakn/i3ajA==", - "license": "MIT" - }, - "node_modules/@types/triple-beam": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", - "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==", - "license": "MIT" - }, - "node_modules/@types/trusted-types": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", - "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "node_modules/@vitest/pretty-format": { + "version": "4.1.8", + "dev": true, "license": "MIT", - "optional": true + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } }, - "node_modules/@types/urijs": { - "version": "1.19.26", - "resolved": "https://registry.npmjs.org/@types/urijs/-/urijs-1.19.26.tgz", - "integrity": "sha512-wkXrVzX5yoqLnndOwFsieJA7oKM8cNkOKJtf/3vVGSUFkWDKZvFHpIl9Pvqb/T9UsawBBFMTTD8xu7sK5MWuvg==", - "license": "MIT" + "node_modules/@vitest/runner": { + "version": "4.1.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.1.8", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } }, - "node_modules/abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "node_modules/@vitest/snapshot": { + "version": "4.1.8", + "dev": true, "license": "MIT", "dependencies": { - "event-target-shim": "^5.0.0" + "@vitest/pretty-format": "4.1.8", + "@vitest/utils": "4.1.8", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" }, - "engines": { - "node": ">=6.5" + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/accepts": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "node_modules/@vitest/spy": { + "version": "4.1.8", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.1.8", + "dev": true, "license": "MIT", "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" + "@vitest/pretty-format": "4.1.8", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" }, - "engines": { - "node": ">= 0.6" + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "node_modules/abort-controller": { + "version": "3.0.0", "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, "engines": { - "node": ">= 14" + "node": ">=6.5" } }, + "node_modules/abstract-logging": { + "version": "2.0.1", + "license": "MIT" + }, "node_modules/ajv": { "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", - "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -1615,8 +2104,6 @@ }, "node_modules/ajv-draft-04": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", - "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", "license": "MIT", "peerDependencies": { "ajv": "^8.5.0" @@ -1627,10 +2114,15 @@ } } }, + "node_modules/ajv-errors": { + "version": "3.0.0", + "license": "MIT", + "peerDependencies": { + "ajv": "^8.0.1" + } + }, "node_modules/ajv-formats": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", "license": "MIT", "dependencies": { "ajv": "^8.0.0" @@ -1646,8 +2138,6 @@ }, "node_modules/ansi-regex": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "license": "MIT", "engines": { "node": ">=8" @@ -1655,8 +2145,6 @@ }, "node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -1668,22 +2156,22 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/append-field": { + "node_modules/anynum": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", - "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], "license": "MIT" }, "node_modules/argparse": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "license": "Python-2.0" }, "node_modules/array-buffer-byte-length": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", - "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -1698,8 +2186,6 @@ }, "node_modules/arraybuffer.prototype.slice": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", - "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.1", @@ -1717,10 +2203,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/assertion-error": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, "node_modules/astring": { "version": "1.9.0", - "resolved": "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz", - "integrity": "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==", "license": "MIT", "bin": { "astring": "bin/astring" @@ -1728,23 +2220,24 @@ }, "node_modules/async": { "version": "3.2.6", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", - "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", "license": "MIT" }, "node_modules/async-function": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", - "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", "license": "MIT", "engines": { "node": ">= 0.4" } }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/available-typed-arrays": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "license": "MIT", "dependencies": { "possible-typed-array-names": "^1.0.0" @@ -1756,16 +2249,34 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/avvio": { + "version": "9.2.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "@fastify/error": "^4.0.0", + "fastq": "^1.17.1" + } + }, "node_modules/balanced-match": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/bath-es5": { + "version": "3.0.3", "license": "MIT" }, "node_modules/better-ajv-errors": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/better-ajv-errors/-/better-ajv-errors-2.0.3.tgz", - "integrity": "sha512-t1vxUP+vYKsaYi/BbKo2K98nEAZmfi4sjwvmRT8aOPDzPJeAtLurfoIDazVkLILxO4K+Sw4YrLYnBQ46l6pePg==", "license": "Apache-2.0", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -1781,91 +2292,21 @@ "ajv": "4.11.8 - 8" } }, - "node_modules/body-parser": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", - "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", - "license": "MIT", - "dependencies": { - "bytes": "^3.1.2", - "content-type": "^1.0.5", - "debug": "^4.4.3", - "http-errors": "^2.0.0", - "iconv-lite": "^0.7.0", - "on-finished": "^2.4.1", - "qs": "^6.14.1", - "raw-body": "^3.0.1", - "type-is": "^2.0.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/body-parser/node_modules/iconv-lite": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", - "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, "node_modules/brace-expansion": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", - "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "version": "1.1.15", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "license": "MIT" - }, - "node_modules/busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", - "dependencies": { - "streamsearch": "^1.1.0" - }, - "engines": { - "node": ">=10.16.0" - } - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/call-bind": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", - "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "version": "1.0.9", "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.0", - "es-define-property": "^1.0.0", - "get-intrinsic": "^1.2.4", + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", "set-function-length": "^1.2.2" }, "engines": { @@ -1877,8 +2318,6 @@ }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -1890,8 +2329,6 @@ }, "node_modules/call-bound": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -1906,23 +2343,10 @@ }, "node_modules/call-me-maybe": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", - "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==", - "license": "MIT" - }, - "node_modules/camelize": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz", - "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "license": "MIT" }, "node_modules/case-anything": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/case-anything/-/case-anything-3.1.2.tgz", - "integrity": "sha512-wljhAjDDIv/hM2FzgJnYQg90AWmZMNtESCjTeLH680qTzdo0nErlCxOmgzgX4ZsZAtIvqHyD87ES8QyriXB+BQ==", "license": "MIT", "engines": { "node": ">=18" @@ -1931,10 +2355,16 @@ "url": "https://github.com/sponsors/mesqueeb" } }, + "node_modules/chai": { + "version": "6.2.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -1949,23 +2379,13 @@ }, "node_modules/charset": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/charset/-/charset-1.0.1.tgz", - "integrity": "sha512-6dVyOOYjpfFcL1Y4qChrAoQLRHvj2ziyhcm0QJlhOcAhykL/k1kTUPbeo+87MNRTRdk2OIIsIXbuF3x2wi5EXg==", "license": "MIT", "engines": { "node": ">=4.0.0" } }, - "node_modules/classnames": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", - "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", - "license": "MIT" - }, "node_modules/cliui": { "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "license": "ISC", "dependencies": { "string-width": "^4.2.0", @@ -1976,32 +2396,8 @@ "node": ">=12" } }, - "node_modules/clsx": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/color": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/color/-/color-5.0.2.tgz", - "integrity": "sha512-e2hz5BzbUPcYlIRHo8ieAhYgoajrJr+hWoceg6E345TPsATMUKqDgzt8fSXZJJbxfpiPzkWyphz8yn8At7q3fA==", - "license": "MIT", - "dependencies": { - "color-convert": "^3.0.1", - "color-string": "^2.0.0" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -2012,68 +2408,21 @@ }, "node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "license": "MIT" }, - "node_modules/color-string": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-2.1.2.tgz", - "integrity": "sha512-RxmjYxbWemV9gKu4zPgiZagUxbH3RQpEIO77XoSSX0ivgABDZ+h8Zuash/EMFLTI4N9QgFPOJ6JQpPZKFxa+dA==", - "license": "MIT", - "dependencies": { - "color-name": "^2.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/color-string/node_modules/color-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.0.2.tgz", - "integrity": "sha512-9vEt7gE16EW7Eu7pvZnR0abW9z6ufzhXxGXZEVU9IqPdlsUiMwJeJfRtq0zePUmnbHGT9zajca7mX8zgoayo4A==", - "license": "MIT", - "engines": { - "node": ">=12.20" - } - }, - "node_modules/color/node_modules/color-convert": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-3.1.2.tgz", - "integrity": "sha512-UNqkvCDXstVck3kdowtOTWROIJQwafjOfXSmddoDrXo4cewMKmusCeF22Q24zvjR8nwWib/3S/dfyzPItPEiJg==", - "license": "MIT", - "dependencies": { - "color-name": "^2.0.0" - }, - "engines": { - "node": ">=14.6" - } - }, - "node_modules/color/node_modules/color-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.0.2.tgz", - "integrity": "sha512-9vEt7gE16EW7Eu7pvZnR0abW9z6ufzhXxGXZEVU9IqPdlsUiMwJeJfRtq0zePUmnbHGT9zajca7mX8zgoayo4A==", - "license": "MIT", - "engines": { - "node": ">=12.20" - } - }, "node_modules/colorette": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", - "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", + "version": "2.0.20", "license": "MIT" }, "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "license": "MIT" + "version": "9.5.0", + "license": "MIT", + "engines": { + "node": "^12.20.0 || >=14" + } }, "node_modules/compute-gcd": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/compute-gcd/-/compute-gcd-1.2.1.tgz", - "integrity": "sha512-TwMbxBNz0l71+8Sc4czv13h4kEqnchV9igQZBi6QUaz09dnz13juGnnaWWJTRsP3brxOoxeB4SA2WELLw1hCtg==", "dependencies": { "validate.io-array": "^1.0.3", "validate.io-function": "^1.0.2", @@ -2082,8 +2431,6 @@ }, "node_modules/compute-lcm": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/compute-lcm/-/compute-lcm-1.1.2.tgz", - "integrity": "sha512-OFNPdQAXnQhDSKioX8/XYT6sdUlXwpeMjfd6ApxMJfyZ4GxmLR1xvMERctlYhlHwIiz6CSpBc2+qYKjHGZw4TQ==", "dependencies": { "compute-gcd": "^1.2.1", "validate.io-array": "^1.0.3", @@ -2093,120 +2440,30 @@ }, "node_modules/concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "license": "MIT" }, - "node_modules/concat-stream": { + "node_modules/convert-source-map": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", - "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", - "engines": [ - "node >= 6.0" - ], - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.0.2", - "typedarray": "^0.0.6" - } - }, - "node_modules/content-disposition": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", - "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/core-js": { - "version": "3.46.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.46.0.tgz", - "integrity": "sha512-vDMm9B0xnqqZ8uSBpZ8sNtRtOdmfShrvT6h2TuQGLs0Is+cR0DYbj/KWP6ALVNbWPpqA/qPLoOuppJN07humpA==", - "hasInstallScript": true, - "license": "MIT", - "peer": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, "license": "MIT" }, - "node_modules/cors": { - "version": "2.8.6", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", - "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "node_modules/cookie": { + "version": "1.1.1", "license": "MIT", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, "engines": { - "node": ">= 0.10" + "node": ">=18" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/express" } }, - "node_modules/css-color-keywords": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", - "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==", - "license": "ISC", - "engines": { - "node": ">=4" - } - }, - "node_modules/css-to-react-native": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz", - "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==", - "license": "MIT", - "dependencies": { - "camelize": "^1.0.0", - "css-color-keywords": "^1.0.0", - "postcss-value-parser": "^4.0.2" - } - }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "node_modules/core-util-is": { + "version": "1.0.3", "license": "MIT" }, "node_modules/data-view-buffer": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", - "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -2222,8 +2479,6 @@ }, "node_modules/data-view-byte-length": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", - "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -2239,8 +2494,6 @@ }, "node_modules/data-view-byte-offset": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", - "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -2256,8 +2509,6 @@ }, "node_modules/debug": { "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -2271,15 +2522,8 @@ } } }, - "node_modules/decko": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decko/-/decko-1.2.0.tgz", - "integrity": "sha512-m8FnyHXV1QX+S1cl+KPFDIl6NMkxtKsy6+U/aYyjrOqWMuwAwYWu7ePqrsUHtDR5Y8Yk2pi/KIDSgF+vT4cPOQ==" - }, "node_modules/define-data-property": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", @@ -2295,8 +2539,6 @@ }, "node_modules/define-properties": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "license": "MIT", "dependencies": { "define-data-property": "^1.0.1", @@ -2310,37 +2552,34 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "node_modules/dependency-graph": { + "version": "0.11.0", "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">= 0.6.0" } }, - "node_modules/dependency-graph": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", - "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==", + "node_modules/dequal": { + "version": "2.0.3", "license": "MIT", "engines": { - "node": ">= 0.6.0" + "node": ">=6" } }, - "node_modules/dompurify": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.0.tgz", - "integrity": "sha512-r+f6MYR1gGN1eJv0TVQbhA7if/U7P87cdPl3HN5rikqaBSBxLiCb/b9O+2eG0cxz0ghyU+mU1QkbsOwERMYlWQ==", - "license": "(MPL-2.0 OR Apache-2.0)", - "optionalDependencies": { - "@types/trusted-types": "^2.0.7" + "node_modules/dereference-json-schema": { + "version": "0.2.2", + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" } }, "node_modules/dunder-proto": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", @@ -2351,37 +2590,12 @@ "node": ">= 0.4" } }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "license": "MIT" - }, "node_modules/emoji-regex": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, - "node_modules/enabled": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", - "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==", "license": "MIT" }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/es-abstract": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", - "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", + "version": "1.24.2", "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.2", @@ -2448,8 +2662,6 @@ }, "node_modules/es-aggregate-error": { "version": "1.0.14", - "resolved": "https://registry.npmjs.org/es-aggregate-error/-/es-aggregate-error-1.0.14.tgz", - "integrity": "sha512-3YxX6rVb07B5TV11AV5wsL7nQCHXNwoHPsQC8S4AmBiqYhyNCJ5BRKXkXyDJvs8QzXN20NgRtxe3dEEQD9NLHA==", "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", @@ -2470,8 +2682,6 @@ }, "node_modules/es-define-property": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -2479,17 +2689,18 @@ }, "node_modules/es-errors": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "license": "MIT", "engines": { "node": ">= 0.4" } }, + "node_modules/es-module-lexer": { + "version": "2.1.0", + "dev": true, + "license": "MIT" + }, "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "version": "1.1.2", "license": "MIT", "dependencies": { "es-errors": "^1.3.0" @@ -2500,8 +2711,6 @@ }, "node_modules/es-set-tostringtag": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -2515,8 +2724,6 @@ }, "node_modules/es-to-primitive": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", - "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", "license": "MIT", "dependencies": { "is-callable": "^1.2.7", @@ -2532,157 +2739,132 @@ }, "node_modules/es6-promise": { "version": "3.3.1", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", - "integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==", "license": "MIT" }, + "node_modules/esbuild": { + "version": "0.28.0", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.0", + "@esbuild/android-arm": "0.28.0", + "@esbuild/android-arm64": "0.28.0", + "@esbuild/android-x64": "0.28.0", + "@esbuild/darwin-arm64": "0.28.0", + "@esbuild/darwin-x64": "0.28.0", + "@esbuild/freebsd-arm64": "0.28.0", + "@esbuild/freebsd-x64": "0.28.0", + "@esbuild/linux-arm": "0.28.0", + "@esbuild/linux-arm64": "0.28.0", + "@esbuild/linux-ia32": "0.28.0", + "@esbuild/linux-loong64": "0.28.0", + "@esbuild/linux-mips64el": "0.28.0", + "@esbuild/linux-ppc64": "0.28.0", + "@esbuild/linux-riscv64": "0.28.0", + "@esbuild/linux-s390x": "0.28.0", + "@esbuild/linux-x64": "0.28.0", + "@esbuild/netbsd-arm64": "0.28.0", + "@esbuild/netbsd-x64": "0.28.0", + "@esbuild/openbsd-arm64": "0.28.0", + "@esbuild/openbsd-x64": "0.28.0", + "@esbuild/openharmony-arm64": "0.28.0", + "@esbuild/sunos-x64": "0.28.0", + "@esbuild/win32-arm64": "0.28.0", + "@esbuild/win32-ia32": "0.28.0", + "@esbuild/win32-x64": "0.28.0" + } + }, "node_modules/escalade": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT" - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "node_modules/estree-walker": { + "version": "3.0.3", + "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.6" + "dependencies": { + "@types/estree": "^1.0.0" } }, "node_modules/event-target-shim": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/eventemitter3": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", - "license": "MIT" + "node_modules/expect-type": { + "version": "1.3.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } }, "node_modules/expr-eval-fork": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/expr-eval-fork/-/expr-eval-fork-3.0.3.tgz", - "integrity": "sha512-BhC+hbc5lIVjygr840n5DEkW3MQq7H9o+mc1/N7Z5uIiCFVyESLL5DIE7LNq4CYUNxy+XjA+3jRrL/h0Kt2xcg==", "license": "MIT", "engines": { "node": ">=16.9.0" } }, - "node_modules/express": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", - "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", - "license": "MIT", - "dependencies": { - "accepts": "^2.0.0", - "body-parser": "^2.2.1", - "content-disposition": "^1.0.0", - "content-type": "^1.0.5", - "cookie": "^0.7.1", - "cookie-signature": "^1.2.1", - "debug": "^4.4.0", - "depd": "^2.0.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "finalhandler": "^2.1.0", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "merge-descriptors": "^2.0.0", - "mime-types": "^3.0.0", - "on-finished": "^2.4.1", - "once": "^1.4.0", - "parseurl": "^1.3.3", - "proxy-addr": "^2.0.7", - "qs": "^6.14.0", - "range-parser": "^1.2.1", - "router": "^2.2.0", - "send": "^1.1.0", - "serve-static": "^2.2.0", - "statuses": "^2.0.1", - "type-is": "^2.0.1", - "vary": "^1.1.2" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } + "node_modules/fast-decode-uri-component": { + "version": "1.0.1", + "license": "MIT" }, - "node_modules/express-openapi-validator": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/express-openapi-validator/-/express-openapi-validator-5.6.2.tgz", - "integrity": "sha512-fkDn4+ImUC4HTJ1g0cek/ItqYhmEO19AglJd2Iw2OJco0jLIbxIlDGVazmXbvvYeziU4Bnah2h+S2tb6NtWg8w==", + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "license": "MIT" + }, + "node_modules/fast-json-stringify": { + "version": "6.4.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], "license": "MIT", "dependencies": { - "@apidevtools/json-schema-ref-parser": "^14.2.1", - "@types/multer": "^2.0.0", - "ajv": "^8.17.1", - "ajv-draft-04": "^1.0.0", + "@fastify/merge-json-schemas": "^0.2.0", + "ajv": "^8.12.0", "ajv-formats": "^3.0.1", - "content-type": "^1.0.5", - "json-schema-traverse": "^1.0.0", - "lodash.clonedeep": "^4.5.0", - "lodash.get": "^4.4.2", - "media-typer": "^1.1.0", - "multer": "^2.0.2", - "ono": "^7.1.3", - "path-to-regexp": "^8.3.0", - "qs": "^6.14.1" - }, - "peerDependencies": { - "express": "*" - } - }, - "node_modules/express/node_modules/cookie-signature": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", - "license": "MIT", - "engines": { - "node": ">=6.6.0" + "fast-uri": "^3.0.0", + "json-schema-ref-resolver": "^3.0.0", + "rfdc": "^1.2.0" } }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "license": "MIT" - }, "node_modules/fast-memoize": { "version": "2.5.2", - "resolved": "https://registry.npmjs.org/fast-memoize/-/fast-memoize-2.5.2.tgz", - "integrity": "sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw==", "license": "MIT" }, + "node_modules/fast-querystring": { + "version": "1.1.2", + "license": "MIT", + "dependencies": { + "fast-decode-uri-component": "^1.0.1" + } + }, "node_modules/fast-safe-stringify": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "version": "3.1.2", "funding": [ { "type": "github", @@ -2696,9 +2878,7 @@ "license": "BSD-3-Clause" }, "node_modules/fast-xml-builder": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.1.2.tgz", - "integrity": "sha512-NJAmiuVaJEjVa7TjLZKlYd7RqmzOC91EtPFXHvlTcqBVo50Qh7XV5IwvXi1c7NRz2Q/majGX9YLcwJtWgHjtkA==", + "version": "1.2.0", "funding": [ { "type": "github", @@ -2707,13 +2887,12 @@ ], "license": "MIT", "dependencies": { - "path-expression-matcher": "^1.1.3" + "path-expression-matcher": "^1.5.0", + "xml-naming": "^0.1.0" } }, "node_modules/fast-xml-parser": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.5.3.tgz", - "integrity": "sha512-Ymnuefk6VzAhT3SxLzVUw+nMio/wB1NGypHkgetwtXcK1JfryaHk4DWQFGVwQ9XgzyS5iRZ7C2ZGI4AMsdMZ6A==", + "version": "5.8.0", "funding": [ { "type": "github", @@ -2722,56 +2901,91 @@ ], "license": "MIT", "dependencies": { - "fast-xml-builder": "^1.1.2", - "path-expression-matcher": "^1.1.3", - "strnum": "^2.1.2" + "@nodable/entities": "^2.1.0", + "fast-xml-builder": "^1.2.0", + "path-expression-matcher": "^1.5.0", + "strnum": "^2.3.0", + "xml-naming": "^0.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, - "node_modules/fecha": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", - "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==", - "license": "MIT" + "node_modules/fastify": { + "version": "5.8.5", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "@fastify/ajv-compiler": "^4.0.5", + "@fastify/error": "^4.0.0", + "@fastify/fast-json-stringify-compiler": "^5.0.0", + "@fastify/proxy-addr": "^5.0.0", + "abstract-logging": "^2.0.1", + "avvio": "^9.0.0", + "fast-json-stringify": "^6.0.0", + "find-my-way": "^9.0.0", + "light-my-request": "^6.0.0", + "pino": "^9.14.0 || ^10.1.0", + "process-warning": "^5.0.0", + "rfdc": "^1.3.1", + "secure-json-parse": "^4.0.0", + "semver": "^7.6.0", + "toad-cache": "^3.7.0" + } + }, + "node_modules/fastq": { + "version": "1.20.1", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } }, "node_modules/file-type": { "version": "3.9.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", - "integrity": "sha512-RLoqTXE8/vPmMuTI88DAzhMYC99I8BWv7zYP4A1puo5HIjEJ5EX48ighy4ZyKMG9EDXxBgW6e++cn7d1xuFghA==", "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/finalhandler": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", - "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "node_modules/find-my-way": { + "version": "9.6.0", "license": "MIT", "dependencies": { - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "on-finished": "^2.4.1", - "parseurl": "^1.3.3", - "statuses": "^2.0.1" + "fast-deep-equal": "^3.1.3", + "fast-querystring": "^1.0.0", + "safe-regex2": "^5.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">=20" } }, - "node_modules/fn.name": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", - "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==", - "license": "MIT" - }, "node_modules/for-each": { "version": "0.3.5", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", - "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", "license": "MIT", "dependencies": { "is-callable": "^1.2.7" @@ -2783,34 +2997,24 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/foreach": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.6.tgz", - "integrity": "sha512-k6GAGDyqLe9JaebCsFCoudPPWfihKu8pylYXRlqP1J7ms39iPoTtk2fviNglIeQEwdh0bQeKJ01ZPyuyQvKzwg==", - "license": "MIT" - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "node_modules/foreach": { + "version": "2.0.6", + "license": "MIT" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "dev": true, "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">= 0.8" + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, "node_modules/function-bind": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2818,8 +3022,6 @@ }, "node_modules/function.prototype.name": { "version": "1.1.8", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", - "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -2838,8 +3040,6 @@ }, "node_modules/functions-have-names": { "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2847,8 +3047,6 @@ }, "node_modules/generator-function": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", - "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -2856,8 +3054,6 @@ }, "node_modules/get-caller-file": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" @@ -2865,8 +3061,6 @@ }, "node_modules/get-intrinsic": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -2889,8 +3083,6 @@ }, "node_modules/get-proto": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", @@ -2902,8 +3094,6 @@ }, "node_modules/get-symbol-description": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", - "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -2917,63 +3107,8 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/glob": { - "version": "13.0.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", - "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", - "license": "BlueOak-1.0.0", - "dependencies": { - "minimatch": "^10.2.2", - "minipass": "^7.1.3", - "path-scurry": "^2.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/globalthis": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", "license": "MIT", "dependencies": { "define-properties": "^1.2.1", @@ -2988,8 +3123,6 @@ }, "node_modules/gopd": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -3000,38 +3133,13 @@ }, "node_modules/graphlib": { "version": "2.1.8", - "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz", - "integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==", "license": "MIT", "dependencies": { "lodash": "^4.17.15" } }, - "node_modules/handlebars": { - "version": "4.7.9", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", - "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", - "license": "MIT", - "dependencies": { - "minimist": "^1.2.5", - "neo-async": "^2.6.2", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "handlebars": "bin/handlebars" - }, - "engines": { - "node": ">=0.4.7" - }, - "optionalDependencies": { - "uglify-js": "^3.1.4" - } - }, "node_modules/has-bigints": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", - "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -3042,8 +3150,6 @@ }, "node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "license": "MIT", "engines": { "node": ">=8" @@ -3051,8 +3157,6 @@ }, "node_modules/has-property-descriptors": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" @@ -3063,8 +3167,6 @@ }, "node_modules/has-proto": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", - "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", "license": "MIT", "dependencies": { "dunder-proto": "^1.0.0" @@ -3078,8 +3180,6 @@ }, "node_modules/has-symbols": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -3090,8 +3190,6 @@ }, "node_modules/has-tostringtag": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" @@ -3104,9 +3202,7 @@ } }, "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "version": "2.0.4", "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -3115,60 +3211,16 @@ "node": ">= 0.4" } }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "license": "MIT", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-errors/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/http-reasons": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/http-reasons/-/http-reasons-0.1.0.tgz", - "integrity": "sha512-P6kYh0lKZ+y29T2Gqz+RlC9WBLhKe8kDmcJ+A+611jFfxdPsbMRQ5aNmFRM3lENqFkK+HTTL+tlQviAiv0AbLQ==", "license": "Apache-2.0" }, "node_modules/http2-client": { "version": "1.3.5", - "resolved": "https://registry.npmjs.org/http2-client/-/http2-client-1.3.5.tgz", - "integrity": "sha512-EC2utToWl4RKfs5zd36Mxq7nzHHBuomZboI0yYL6Y0RmBgT7Sgkq4rQ0ezFTYoIsSs7Tm9SJe+o2FcAg6GBhGA==", "license": "MIT" }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/iconv-lite": { "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -3177,16 +3229,30 @@ "node": ">=0.10.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/immediate": { "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", "license": "MIT" }, "node_modules/immer": { "version": "9.0.21", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", - "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", "license": "MIT", "funding": { "type": "opencollective", @@ -3195,14 +3261,10 @@ }, "node_modules/inherits": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, "node_modules/internal-slot": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", - "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -3213,19 +3275,8 @@ "node": ">= 0.4" } }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, "node_modules/is-array-buffer": { "version": "3.0.5", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", - "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -3241,8 +3292,6 @@ }, "node_modules/is-async-function": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", - "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", "license": "MIT", "dependencies": { "async-function": "^1.0.0", @@ -3260,8 +3309,6 @@ }, "node_modules/is-bigint": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", - "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", "license": "MIT", "dependencies": { "has-bigints": "^1.0.2" @@ -3275,8 +3322,6 @@ }, "node_modules/is-boolean-object": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", - "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -3291,8 +3336,6 @@ }, "node_modules/is-callable": { "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -3303,8 +3346,6 @@ }, "node_modules/is-data-view": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", - "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -3320,8 +3361,6 @@ }, "node_modules/is-date-object": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", - "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -3336,8 +3375,6 @@ }, "node_modules/is-finalizationregistry": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", - "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3" @@ -3351,8 +3388,6 @@ }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "license": "MIT", "engines": { "node": ">=8" @@ -3360,8 +3395,6 @@ }, "node_modules/is-generator-function": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", - "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", "license": "MIT", "dependencies": { "call-bound": "^1.0.4", @@ -3379,8 +3412,6 @@ }, "node_modules/is-map": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", - "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -3391,8 +3422,6 @@ }, "node_modules/is-negative-zero": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -3403,8 +3432,6 @@ }, "node_modules/is-number-object": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", - "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -3417,16 +3444,8 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-promise": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", - "license": "MIT" - }, "node_modules/is-regex": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -3443,8 +3462,6 @@ }, "node_modules/is-set": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", - "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -3455,8 +3472,6 @@ }, "node_modules/is-shared-array-buffer": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", - "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3" @@ -3468,22 +3483,8 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-string": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", - "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -3498,8 +3499,6 @@ }, "node_modules/is-symbol": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", - "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -3515,8 +3514,6 @@ }, "node_modules/is-typed-array": { "version": "1.1.15", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", - "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", "license": "MIT", "dependencies": { "which-typed-array": "^1.1.16" @@ -3530,8 +3527,6 @@ }, "node_modules/is-weakmap": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", - "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -3542,8 +3537,6 @@ }, "node_modules/is-weakref": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", - "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3" @@ -3557,8 +3550,6 @@ }, "node_modules/is-weakset": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", - "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -3572,15 +3563,18 @@ } }, "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "version": "1.0.0", "license": "MIT" }, + "node_modules/iterare": { + "version": "1.2.1", + "license": "ISC", + "engines": { + "node": ">=6" + } + }, "node_modules/js-levenshtein": { "version": "1.1.6", - "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", - "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -3588,14 +3582,20 @@ }, "node_modules/js-tokens": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "version": "4.2.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -3606,8 +3606,6 @@ }, "node_modules/jsep": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.4.0.tgz", - "integrity": "sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==", "license": "MIT", "engines": { "node": ">= 10.16.0" @@ -3615,8 +3613,6 @@ }, "node_modules/json-pointer": { "version": "0.6.2", - "resolved": "https://registry.npmjs.org/json-pointer/-/json-pointer-0.6.2.tgz", - "integrity": "sha512-vLWcKbOaXlO+jvRy4qNd+TI1QUPZzfJj1tpJ3vAXDych5XJf93ftpUKe5pKCrzyIIwgBJcOcCVRUfqQP25afBw==", "license": "MIT", "dependencies": { "foreach": "^2.0.4" @@ -3624,8 +3620,6 @@ }, "node_modules/json-schema-compare": { "version": "0.2.2", - "resolved": "https://registry.npmjs.org/json-schema-compare/-/json-schema-compare-0.2.2.tgz", - "integrity": "sha512-c4WYmDKyJXhs7WWvAWm3uIYnfyWFoIp+JEoX34rctVvEkMYCPGhXtvmFFXiffBbxfZsvQ0RNnV5H7GvDF5HCqQ==", "license": "MIT", "dependencies": { "lodash": "^4.17.4" @@ -3633,8 +3627,6 @@ }, "node_modules/json-schema-merge-allof": { "version": "0.8.1", - "resolved": "https://registry.npmjs.org/json-schema-merge-allof/-/json-schema-merge-allof-0.8.1.tgz", - "integrity": "sha512-CTUKmIlPJbsWfzRRnOXz+0MjIqvnleIXwFTzz+t9T86HnYX/Rozria6ZVGLktAU9e+NygNljveP+yxqtQp/Q4w==", "license": "MIT", "dependencies": { "compute-lcm": "^1.1.2", @@ -3645,10 +3637,25 @@ "node": ">=12.0.0" } }, + "node_modules/json-schema-ref-resolver": { + "version": "3.0.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "dequal": "^2.0.3" + } + }, "node_modules/json-schema-to-ts": { "version": "2.7.2", - "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-2.7.2.tgz", - "integrity": "sha512-R1JfqKqbBR4qE8UyBR56Ms30LL62/nlhoz+1UkfI/VE7p54Awu919FZ6ZUPG8zIa3XB65usPJgr1ONVncUGSaQ==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.3", @@ -3661,471 +3668,460 @@ }, "node_modules/json-schema-traverse": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "license": "MIT" }, "node_modules/jsonc-parser": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-2.2.1.tgz", - "integrity": "sha512-o6/yDBYccGvTz1+QFevz6l6OBZ2+fMVu2JZ9CIhzsYRX4mjaK5IyX9eldUdCmga16zlgQxyrj5pt9kzuj2C02w==", "license": "MIT" }, "node_modules/jsonpath-plus": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-10.3.0.tgz", - "integrity": "sha512-8TNmfeTCk2Le33A3vRRwtuworG/L5RrgMvdjhKZxvyShO+mBu2fP50OWUjRLNtvw344DdDarFh9buFAZs5ujeA==", - "license": "MIT", - "dependencies": { - "@jsep-plugin/assignment": "^1.3.0", - "@jsep-plugin/regex": "^1.0.4", - "jsep": "^1.4.0" - }, - "bin": { - "jsonpath": "bin/jsonpath-cli.js", - "jsonpath-plus": "bin/jsonpath-cli.js" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/jsonpath-rfc9535": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/jsonpath-rfc9535/-/jsonpath-rfc9535-1.3.0.tgz", - "integrity": "sha512-3jFHya7oZ45aDxIIdx+/zQARahHXxFSMWBkcBUldfXpLS9VCXDJyTKt35kQfEXLqh0K3Ixw/9xFnvcDStaxh7Q==", - "license": "Apache-2.0", - "engines": { - "node": ">=20" - } - }, - "node_modules/jsonpointer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", - "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jszip": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", - "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", - "license": "(MIT OR GPL-3.0-or-later)", - "dependencies": { - "lie": "~3.3.0", - "pako": "~1.0.2", - "readable-stream": "~2.3.6", - "setimmediate": "^1.0.5" - } - }, - "node_modules/jszip/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "license": "MIT" - }, - "node_modules/jszip/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/jszip/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/jszip/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/kuler": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", - "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", - "license": "MIT" - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/lie": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "license": "MIT", - "dependencies": { - "immediate": "~3.0.5" - } - }, - "node_modules/liquid-json": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/liquid-json/-/liquid-json-0.3.1.tgz", - "integrity": "sha512-wUayTU8MS827Dam6MxgD72Ui+KOSF+u/eIqpatOtjnvgJ0+mnDq33uC2M7J0tPK+upe/DpUAuK4JUU89iBoNKQ==", - "license": "Apache-2.0", - "engines": { - "node": ">=4" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "license": "MIT" - }, - "node_modules/lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", - "license": "MIT" - }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", - "deprecated": "This package is deprecated. Use the optional chaining (?.) operator instead.", - "license": "MIT" - }, - "node_modules/lodash.topath": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/lodash.topath/-/lodash.topath-4.5.2.tgz", - "integrity": "sha512-1/W4dM+35DwvE/iEd1M9ekewOSTlpFekhw9mhAtrwjVqUr83/ilQiyAvmg4tVX7Unkcfl1KC+i9WdaT4B6aQcg==", - "license": "MIT" - }, - "node_modules/logform": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", - "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", - "license": "MIT", - "dependencies": { - "@colors/colors": "1.6.0", - "@types/triple-beam": "^1.3.2", - "fecha": "^4.2.0", - "ms": "^2.1.1", - "safe-stable-stringify": "^2.3.1", - "triple-beam": "^1.3.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/long": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", - "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", - "license": "Apache-2.0" - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "license": "MIT", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lru-cache": { - "version": "11.2.6", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", - "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", - "license": "BlueOak-1.0.0", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/lunr": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", - "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", - "license": "MIT" - }, - "node_modules/mark.js": { - "version": "8.11.1", - "resolved": "https://registry.npmjs.org/mark.js/-/mark.js-8.11.1.tgz", - "integrity": "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==", - "license": "MIT" - }, - "node_modules/marked": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", - "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "version": "10.4.0", "license": "MIT", + "dependencies": { + "@jsep-plugin/assignment": "^1.3.0", + "@jsep-plugin/regex": "^1.0.4", + "jsep": "^1.4.0" + }, "bin": { - "marked": "bin/marked.js" + "jsonpath": "bin/jsonpath-cli.js", + "jsonpath-plus": "bin/jsonpath-cli.js" }, "engines": { - "node": ">= 12" + "node": ">=18.0.0" } }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", + "node_modules/jsonpath-rfc9535": { + "version": "1.3.0", + "license": "Apache-2.0", "engines": { - "node": ">= 0.4" + "node": ">=20" } }, - "node_modules/media-typer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "node_modules/jsonpointer": { + "version": "5.0.1", "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">=0.10.0" } }, - "node_modules/merge-descriptors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node_modules/jszip": { + "version": "3.10.1", + "license": "(MIT OR GPL-3.0-or-later)", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" } }, - "node_modules/mime": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", - "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "node_modules/leven": { + "version": "3.1.0", "license": "MIT", - "bin": { - "mime": "cli.js" - }, "engines": { - "node": ">=10.0.0" + "node": ">=6" } }, - "node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "node_modules/lie": { + "version": "3.3.0", "license": "MIT", - "engines": { - "node": ">= 0.6" + "dependencies": { + "immediate": "~3.0.5" } }, - "node_modules/mime-format": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/mime-format/-/mime-format-2.0.2.tgz", - "integrity": "sha512-Y5ERWVcyh3sby9Fx2U5F1yatiTFjNsqF5NltihTWI9QgNtr5o3dbCZdcKa1l2wyfhnwwoP9HGNxga7LqZLA6gw==", - "license": "Apache-2.0", + "node_modules/light-my-request": { + "version": "6.6.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause", "dependencies": { - "charset": "^1.0.0" + "cookie": "^1.0.1", + "process-warning": "^4.0.0", + "set-cookie-parser": "^2.6.0" } }, - "node_modules/mime-types": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", - "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", - "license": "MIT", + "node_modules/light-my-request/node_modules/process-warning": { + "version": "4.0.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "dev": true, + "license": "MPL-2.0", "dependencies": { - "mime-db": "^1.54.0" + "detect-libc": "^2.0.3" }, "engines": { - "node": ">= 0.6" - } - }, - "node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "*" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "license": "MIT", + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/minipass": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", - "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", - "license": "BlueOak-1.0.0", + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "license": "MIT", - "dependencies": { - "minimist": "^1.2.6" + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" }, - "bin": { - "mkdirp": "bin/cmd.js" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/mobx": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/mobx/-/mobx-6.15.0.tgz", - "integrity": "sha512-UczzB+0nnwGotYSgllfARAqWCJ5e/skuV2K/l+Zyck/H6pJIhLXuBnz+6vn2i211o7DtbE78HQtsYEKICHGI+g==", - "license": "MIT", + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mobx" + "url": "https://opencollective.com/parcel" } }, - "node_modules/mobx-react": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/mobx-react/-/mobx-react-9.2.0.tgz", - "integrity": "sha512-dkGWCx+S0/1mfiuFfHRH8D9cplmwhxOV5CkXMp38u6rQGG2Pv3FWYztS0M7ncR6TyPRQKaTG/pnitInoYE9Vrw==", - "license": "MIT", - "dependencies": { - "mobx-react-lite": "^4.1.0" + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mobx" + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" }, - "peerDependencies": { - "mobx": "^6.9.0", - "react": "^16.8.0 || ^17 || ^18 || ^19" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - }, - "react-native": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/mobx-react-lite": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/mobx-react-lite/-/mobx-react-lite-4.1.1.tgz", - "integrity": "sha512-iUxiMpsvNraCKXU+yPotsOncNNmyeS2B5DKL+TL6Tar/xm+wwNJAubJmtRSeAoYawdZqwv8Z/+5nPRHeQxTiXg==", - "license": "MIT", - "dependencies": { - "use-sync-external-store": "^1.4.0" + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/mobx" + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" }, - "peerDependencies": { - "mobx": "^6.9.0", - "react": "^16.8.0 || ^17 || ^18 || ^19" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/liquid-json": { + "version": "0.3.1", + "license": "Apache-2.0", + "engines": { + "node": ">=4" + } + }, + "node_modules/load-esm": { + "version": "1.0.3", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/Borewit" }, - "react-native": { - "optional": true + { + "type": "buymeacoffee", + "url": "https://buymeacoffee.com/borewit" } + ], + "license": "MIT", + "engines": { + "node": ">=13.2.0" } }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "node_modules/lodash": { + "version": "4.18.1", "license": "MIT" }, - "node_modules/multer": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/multer/-/multer-2.0.2.tgz", - "integrity": "sha512-u7f2xaZ/UG8oLXHvtF/oWTRvT44p9ecwBBqTwgJVq0+4BW1g8OW01TyMEGWBHbyMOYVHXslaut7qEQ1meATXgw==", + "node_modules/lodash.merge": { + "version": "4.6.2", + "license": "MIT" + }, + "node_modules/lodash.topath": { + "version": "4.5.2", + "license": "MIT" + }, + "node_modules/magic-string": { + "version": "0.30.21", + "dev": true, "license": "MIT", "dependencies": { - "append-field": "^1.0.0", - "busboy": "^1.6.0", - "concat-stream": "^2.0.0", - "mkdirp": "^0.5.6", - "object-assign": "^4.1.1", - "type-is": "^1.6.18", - "xtend": "^4.0.2" - }, - "engines": { - "node": ">= 10.16.0" + "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "node_modules/multer/node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "node_modules/math-intrinsics": { + "version": "1.1.0", "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.4" } }, - "node_modules/multer/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "node_modules/mime": { + "version": "3.0.0", "license": "MIT", + "bin": { + "mime": "cli.js" + }, "engines": { - "node": ">= 0.6" + "node": ">=10.0.0" } }, - "node_modules/multer/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", + "node_modules/mime-format": { + "version": "2.0.2", + "license": "Apache-2.0", "dependencies": { - "mime-db": "1.52.0" + "charset": "^1.0.0" + } + }, + "node_modules/minimatch": { + "version": "3.1.5", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">= 0.6" + "node": "*" } }, - "node_modules/multer/node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "node_modules/mock-json-schema": { + "version": "1.1.2", "license": "MIT", "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" + "lodash": "^4.17.21" } }, + "node_modules/ms": { + "version": "2.1.3", + "license": "MIT" + }, "node_modules/nanoid": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", - "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "version": "3.3.12", + "dev": true, "funding": [ { "type": "github", @@ -4140,25 +4136,8 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/negotiator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "license": "MIT" - }, "node_modules/neotraverse": { "version": "0.6.15", - "resolved": "https://registry.npmjs.org/neotraverse/-/neotraverse-0.6.15.tgz", - "integrity": "sha512-HZpdkco+JeXq0G+WWpMJ4NsX3pqb5O7eR9uGz3FfoFt+LYzU8iRWp49nJtud6hsDoywM8tIrDo3gjgmOqJA8LA==", "license": "MIT", "engines": { "node": ">= 10" @@ -4166,8 +4145,6 @@ }, "node_modules/nimma": { "version": "0.2.3", - "resolved": "https://registry.npmjs.org/nimma/-/nimma-0.2.3.tgz", - "integrity": "sha512-1ZOI8J+1PKKGceo/5CT5GfQOG6H8I2BencSK06YarZ2wXwH37BSSUWldqJmMJYA5JfqDqffxDXynt6f11AyKcA==", "license": "Apache-2.0", "dependencies": { "@jsep-plugin/regex": "^1.0.1", @@ -4185,8 +4162,6 @@ }, "node_modules/node-fetch": { "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "license": "MIT", "dependencies": { "whatwg-url": "^5.0.0" @@ -4205,8 +4180,6 @@ }, "node_modules/node-fetch-h2": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/node-fetch-h2/-/node-fetch-h2-2.3.0.tgz", - "integrity": "sha512-ofRW94Ab0T4AOh5Fk8t0h8OBWrmjb0SSB20xh1H8YnPV9EJ+f5AMoYSUQ2zgJ4Iq2HAK0I2l5/Nequ8YzFS3Hg==", "license": "MIT", "dependencies": { "http2-client": "^1.2.5" @@ -4217,8 +4190,6 @@ }, "node_modules/node-readfiles": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/node-readfiles/-/node-readfiles-0.2.0.tgz", - "integrity": "sha512-SU00ZarexNlE4Rjdm83vglt5Y9yiQ+XI1XpflWlb7q7UTN1JUItm69xMeiQCTxtTfnzt+83T8Cx+vI2ED++VDA==", "license": "MIT", "dependencies": { "es6-promise": "^3.2.1" @@ -4226,8 +4197,6 @@ }, "node_modules/oas-kit-common": { "version": "1.0.8", - "resolved": "https://registry.npmjs.org/oas-kit-common/-/oas-kit-common-1.0.8.tgz", - "integrity": "sha512-pJTS2+T0oGIwgjGpw7sIRU8RQMcUoKCDWFLdBqKB2BNmGpbBMH2sdqAaOXUg8OzonZHU0L7vfJu1mJFEiYDWOQ==", "license": "BSD-3-Clause", "dependencies": { "fast-safe-stringify": "^2.0.7" @@ -4235,8 +4204,6 @@ }, "node_modules/oas-linter": { "version": "3.2.2", - "resolved": "https://registry.npmjs.org/oas-linter/-/oas-linter-3.2.2.tgz", - "integrity": "sha512-KEGjPDVoU5K6swgo9hJVA/qYGlwfbFx+Kg2QB/kd7rzV5N8N5Mg6PlsoCMohVnQmo+pzJap/F610qTodKzecGQ==", "license": "BSD-3-Clause", "dependencies": { "@exodus/schemasafe": "^1.0.0-rc.2", @@ -4249,8 +4216,6 @@ }, "node_modules/oas-resolver": { "version": "2.5.6", - "resolved": "https://registry.npmjs.org/oas-resolver/-/oas-resolver-2.5.6.tgz", - "integrity": "sha512-Yx5PWQNZomfEhPPOphFbZKi9W93CocQj18NlD2Pa4GWZzdZpSJvYwoiuurRI7m3SpcChrnO08hkuQDL3FGsVFQ==", "license": "BSD-3-Clause", "dependencies": { "node-fetch-h2": "^2.3.0", @@ -4268,8 +4233,6 @@ }, "node_modules/oas-resolver-browser": { "version": "2.5.6", - "resolved": "https://registry.npmjs.org/oas-resolver-browser/-/oas-resolver-browser-2.5.6.tgz", - "integrity": "sha512-Jw5elT/kwUJrnGaVuRWe1D7hmnYWB8rfDDjBnpQ+RYY/dzAewGXeTexXzt4fGEo6PUE4eqKqPWF79MZxxvMppA==", "license": "BSD-3-Clause", "dependencies": { "node-fetch-h2": "^2.3.0", @@ -4288,8 +4251,6 @@ }, "node_modules/oas-schema-walker": { "version": "1.1.5", - "resolved": "https://registry.npmjs.org/oas-schema-walker/-/oas-schema-walker-1.1.5.tgz", - "integrity": "sha512-2yucenq1a9YPmeNExoUa9Qwrt9RFkjqaMAA1X+U7sbb0AqBeTIdMHky9SQQ6iN94bO5NW0W4TRYXerG+BdAvAQ==", "license": "BSD-3-Clause", "funding": { "url": "https://github.com/Mermade/oas-kit?sponsor=1" @@ -4297,8 +4258,6 @@ }, "node_modules/oas-validator": { "version": "5.0.8", - "resolved": "https://registry.npmjs.org/oas-validator/-/oas-validator-5.0.8.tgz", - "integrity": "sha512-cu20/HE5N5HKqVygs3dt94eYJfBi0TsZvPVXDhbXQHiEityDN+RROTleefoKRKKJ9dFAF2JBkDHgvWj0sjKGmw==", "license": "BSD-3-Clause", "dependencies": { "call-me-maybe": "^1.0.1", @@ -4314,19 +4273,8 @@ "url": "https://github.com/Mermade/oas-kit?sponsor=1" } }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/object-hash": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", "license": "MIT", "engines": { "node": ">= 6" @@ -4334,8 +4282,6 @@ }, "node_modules/object-inspect": { "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -4346,8 +4292,6 @@ }, "node_modules/object-keys": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -4355,8 +4299,6 @@ }, "node_modules/object.assign": { "version": "4.1.7", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", - "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -4373,60 +4315,80 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "node_modules/obug": { + "version": "2.1.1", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT" + }, + "node_modules/on-exit-leak-free": { + "version": "2.1.2", "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, "engines": { - "node": ">= 0.8" + "node": ">=14.0.0" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", + "node_modules/openapi-backend": { + "version": "5.17.0", + "license": "MIT", "dependencies": { - "wrappy": "1" + "@apidevtools/json-schema-ref-parser": "^11.1.0", + "ajv": "^8.6.2", + "bath-es5": "^3.0.3", + "cookie": "^1.0.1", + "dereference-json-schema": "^0.2.1", + "lodash": "^4.17.15", + "mock-json-schema": "^1.0.7", + "openapi-schema-validator": "^12.0.0", + "openapi-types": "^12.0.2", + "qs": "^6.15.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/anttiviljami" } }, - "node_modules/one-time": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", - "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "node_modules/openapi-sampler": { + "version": "1.7.4", "license": "MIT", "dependencies": { - "fn.name": "1.x.x" + "@types/json-schema": "^7.0.7", + "fast-xml-parser": "^5.5.1", + "json-pointer": "0.6.2" } }, - "node_modules/ono": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/ono/-/ono-7.1.3.tgz", - "integrity": "sha512-9jnfVriq7uJM4o5ganUY54ntUm+5EK21EGaQ5NWnkWg3zz5ywbbonlBguRcnmF1/HDiIe3zxNxXcO1YPBmPcQQ==", + "node_modules/openapi-schema-validator": { + "version": "12.1.3", "license": "MIT", "dependencies": { - "@jsdevtools/ono": "7.1.3" + "ajv": "^8.1.0", + "ajv-formats": "^2.0.2", + "lodash.merge": "^4.6.1", + "openapi-types": "^12.1.3" } }, - "node_modules/openapi-sampler": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/openapi-sampler/-/openapi-sampler-1.7.2.tgz", - "integrity": "sha512-OKytvqB5XIaTgA9xtw8W8UTar+uymW2xPVpFN0NihMtuHPdPTGxBEhGnfFnJW5g/gOSIvkP+H0Xh3XhVI9/n7g==", + "node_modules/openapi-schema-validator/node_modules/ajv-formats": { + "version": "2.1.1", "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.7", - "fast-xml-parser": "^5.5.1", - "json-pointer": "0.6.2" + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } } }, "node_modules/openapi-to-postmanv2": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/openapi-to-postmanv2/-/openapi-to-postmanv2-6.0.1.tgz", - "integrity": "sha512-zAjaTwXo07az6jjvZTw4d26QMQsFxZBxTqjj3LQQMDCCuO6+peATQc9bSmAq3QbzvikP+h2WEjTphMcIrcSurg==", + "version": "6.1.0", "license": "Apache-2.0", "dependencies": { "ajv": "^8.11.0", @@ -4457,8 +4419,6 @@ }, "node_modules/openapi-to-postmanv2/node_modules/ajv-formats": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", "license": "MIT", "dependencies": { "ajv": "^8.0.0" @@ -4472,6 +4432,10 @@ } } }, + "node_modules/openapi-to-postmanv2/node_modules/commander": { + "version": "2.20.3", + "license": "MIT" + }, "node_modules/openapi-to-postmanv2/node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -4484,22 +4448,22 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/openapi-to-postmanv2/node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, "node_modules/openapi-types": { "version": "12.1.3", - "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", - "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==", "license": "MIT" }, "node_modules/outdent": { "version": "0.8.0", - "resolved": "https://registry.npmjs.org/outdent/-/outdent-0.8.0.tgz", - "integrity": "sha512-KiOAIsdpUTcAXuykya5fnVVT+/5uS0Q1mrkRHcF89tpieSmY33O/tmc54CqwA+bfhbtEfZUNLHaPUiB9X3jt1A==", "license": "MIT" }, "node_modules/own-keys": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", - "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.6", @@ -4515,29 +4479,14 @@ }, "node_modules/pako": { "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", "license": "(MIT AND Zlib)" }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/path-browserify": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", - "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", "license": "MIT" }, "node_modules/path-expression-matcher": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.1.3.tgz", - "integrity": "sha512-qdVgY8KXmVdJZRSS1JdEPOKPdTiEK/pi0RkcT2sw1RhXxohdujUlJFPuS1TSkevZ9vzd3ZlL7ULl1MHGTApKzQ==", + "version": "1.5.0", "funding": [ { "type": "github", @@ -4549,48 +4498,25 @@ "node": ">=14.0.0" } }, - "node_modules/path-scurry": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", - "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/path-to-regexp": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", - "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", + "version": "8.4.2", "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/express" } }, - "node_modules/perfect-scrollbar": { - "version": "1.5.6", - "resolved": "https://registry.npmjs.org/perfect-scrollbar/-/perfect-scrollbar-1.5.6.tgz", - "integrity": "sha512-rixgxw3SxyJbCaSpo1n35A/fwI1r2rdwMKOTCg/AcG+xOEyZcE8UHVjpZMFCVImzsFoCZeJTT+M/rdEIQYO2nw==", + "node_modules/pathe": { + "version": "2.0.3", + "dev": true, "license": "MIT" }, "node_modules/picocolors": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "license": "ISC" }, "node_modules/picomatch": { "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "license": "MIT", "engines": { "node": ">=12" @@ -4599,31 +4525,46 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pluralize": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", - "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "node_modules/pino": { + "version": "10.3.1", "license": "MIT", - "engines": { - "node": ">=4" + "dependencies": { + "@pinojs/redact": "^0.4.0", + "atomic-sleep": "^1.0.0", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^3.0.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^5.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^4.0.1", + "thread-stream": "^4.0.0" + }, + "bin": { + "pino": "bin.js" } }, - "node_modules/polished": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/polished/-/polished-4.3.1.tgz", - "integrity": "sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==", + "node_modules/pino-abstract-transport": { + "version": "3.0.0", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.17.8" - }, + "split2": "^4.0.0" + } + }, + "node_modules/pino-std-serializers": { + "version": "7.1.0", + "license": "MIT" + }, + "node_modules/pluralize": { + "version": "8.0.0", + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=4" } }, "node_modules/pony-cause": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pony-cause/-/pony-cause-1.1.1.tgz", - "integrity": "sha512-PxkIc/2ZpLiEzQXu5YRDOUgBlfGYBY8156HY5ZcRAwwonMk5W/MrJP2LLkG/hF7GEQzaHo2aS7ho6ZLCOvf+6g==", "license": "0BSD", "engines": { "node": ">=12.0.0" @@ -4631,17 +4572,14 @@ }, "node_modules/possible-typed-array-names": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", - "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/postcss": { - "version": "8.4.49", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", - "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "version": "8.5.15", + "dev": true, "funding": [ { "type": "opencollective", @@ -4658,7 +4596,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.7", + "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -4666,16 +4604,8 @@ "node": "^10 || ^12 || >=14" } }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "license": "MIT" - }, "node_modules/postman-collection": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/postman-collection/-/postman-collection-5.2.0.tgz", - "integrity": "sha512-ktjlchtpoCw+FZRg+WwnGWH1w9oQDNUBLSRh+9ETPqFAz3SupqHqRuMh74xjQ+PvTWY/WH2JR4ZW+1sH58Ul1g==", + "version": "5.3.0", "license": "Apache-2.0", "dependencies": { "@faker-js/faker": "5.5.3", @@ -4683,331 +4613,115 @@ "http-reasons": "0.1.0", "iconv-lite": "0.6.3", "liquid-json": "0.3.1", - "lodash": "4.17.21", + "lodash": "4.17.23", "mime": "3.0.0", "mime-format": "2.0.2", "postman-url-encoder": "3.0.8", "semver": "7.7.1", "uuid": "8.3.2" }, - "engines": { - "node": ">=18" - } - }, - "node_modules/postman-url-encoder": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/postman-url-encoder/-/postman-url-encoder-3.0.8.tgz", - "integrity": "sha512-EOgUMBazo7JNP4TDrd64TsooCiWzzo4143Ws8E8WYGEpn2PKpq+S4XRTDhuRTYHm3VKOpUZs7ZYZq7zSDuesqA==", - "license": "Apache-2.0", - "dependencies": { - "punycode": "^2.3.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/prismjs": { - "version": "1.30.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", - "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "license": "MIT" - }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/protobufjs": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.6.tgz", - "integrity": "sha512-M71sTMB146U3u0di3yup8iM+zv8yPRNQVr1KK4tyBitl3qFvEGucq/rGDRShD2rsJhtN02RJaJ7j5X5hmy8SJg==", - "hasInstallScript": true, - "license": "BSD-3-Clause", - "dependencies": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.5", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.1", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.1", - "@types/node": ">=13.7.0", - "long": "^5.0.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "license": "MIT", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz", - "integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "license": "MIT", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.1.tgz", - "integrity": "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==", - "license": "MIT", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.7.0", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/raw-body/node_modules/iconv-lite": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", - "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "engines": { + "node": ">=18" } }, - "node_modules/react": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", - "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", - "license": "MIT", + "node_modules/postman-collection/node_modules/@faker-js/faker": { + "version": "5.5.3", + "license": "MIT" + }, + "node_modules/postman-collection/node_modules/lodash": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "license": "MIT" + }, + "node_modules/postman-collection/node_modules/semver": { + "version": "7.7.1", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, "engines": { - "node": ">=0.10.0" + "node": ">=10" } }, - "node_modules/react-dom": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", - "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", - "license": "MIT", + "node_modules/postman-url-encoder": { + "version": "3.0.8", + "license": "Apache-2.0", "dependencies": { - "scheduler": "^0.27.0" + "punycode": "^2.3.1" }, - "peerDependencies": { - "react": "^19.2.4" + "engines": { + "node": ">=10" } }, - "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "node_modules/process-nextick-args": { + "version": "2.0.1", "license": "MIT" }, - "node_modules/react-tabs": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/react-tabs/-/react-tabs-6.1.0.tgz", - "integrity": "sha512-6QtbTRDKM+jA/MZTTefvigNxo0zz+gnBTVFw2CFVvq+f2BuH0nF0vDLNClL045nuTAdOoK/IL1vTP0ZLX0DAyQ==", - "license": "MIT", - "dependencies": { - "clsx": "^2.0.0", - "prop-types": "^15.5.0" - }, - "peerDependencies": { - "react": "^18.0.0 || ^19.0.0" - } + "node_modules/process-warning": { + "version": "5.0.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "node_modules/punycode": { + "version": "2.3.1", "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, "engines": { - "node": ">= 6" + "node": ">=6" } }, - "node_modules/redoc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/redoc/-/redoc-2.5.1.tgz", - "integrity": "sha512-LmqA+4A3CmhTllGG197F0arUpmChukAj9klfSdxNRemT9Hr07xXr7OGKu4PHzBs359sgrJ+4JwmOlM7nxLPGMg==", - "license": "MIT", + "node_modules/qs": { + "version": "6.15.2", + "license": "BSD-3-Clause", "dependencies": { - "@redocly/openapi-core": "^1.4.0", - "classnames": "^2.3.2", - "decko": "^1.2.0", - "dompurify": "^3.2.4", - "eventemitter3": "^5.0.1", - "json-pointer": "^0.6.2", - "lunr": "^2.3.9", - "mark.js": "^8.11.1", - "marked": "^4.3.0", - "mobx-react": "9.2.0", - "openapi-sampler": "^1.5.0", - "path-browserify": "^1.0.1", - "perfect-scrollbar": "^1.5.5", - "polished": "^4.2.2", - "prismjs": "^1.29.0", - "prop-types": "^15.8.1", - "react-tabs": "^6.0.2", - "slugify": "~1.4.7", - "stickyfill": "^1.1.1", - "swagger2openapi": "^7.0.8", - "url-template": "^2.0.8" + "side-channel": "^1.1.0" }, "engines": { - "node": ">=6.9", - "npm": ">=3.0.0" + "node": ">=0.6" }, - "peerDependencies": { - "core-js": "^3.1.4", - "mobx": "^6.0.4", - "react": "^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "styled-components": "^4.1.1 || ^5.1.1 || ^6.0.5" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/redoc/node_modules/@redocly/config": { - "version": "0.22.2", - "resolved": "https://registry.npmjs.org/@redocly/config/-/config-0.22.2.tgz", - "integrity": "sha512-roRDai8/zr2S9YfmzUfNhKjOF0NdcOIqF7bhf4MVC5UxpjIysDjyudvlAiVbpPHp3eDRWbdzUgtkK1a7YiDNyQ==", + "node_modules/quick-format-unescaped": { + "version": "4.0.4", "license": "MIT" }, - "node_modules/redoc/node_modules/@redocly/openapi-core": { - "version": "1.34.5", - "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.34.5.tgz", - "integrity": "sha512-0EbE8LRbkogtcCXU7liAyC00n9uNG9hJ+eMyHFdUsy9lB/WGqnEBgwjA9q2cyzAVcdTkQqTBBU1XePNnN3OijA==", + "node_modules/readable-stream": { + "version": "2.3.8", "license": "MIT", "dependencies": { - "@redocly/ajv": "^8.11.2", - "@redocly/config": "^0.22.0", - "colorette": "^1.2.0", - "https-proxy-agent": "^7.0.5", - "js-levenshtein": "^1.1.6", - "js-yaml": "^4.1.0", - "minimatch": "^5.0.1", - "pluralize": "^8.0.0", - "yaml-ast-parser": "0.0.43" - }, - "engines": { - "node": ">=18.17.0", - "npm": ">=9.5.0" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "node_modules/redoc/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "node_modules/real-require": { + "version": "0.2.0", "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/redoc/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, "engines": { - "node": ">=10" + "node": ">= 12.13.0" } }, + "node_modules/reflect-metadata": { + "version": "0.2.2", + "license": "Apache-2.0" + }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", - "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -5028,8 +4742,6 @@ }, "node_modules/reftools": { "version": "1.1.9", - "resolved": "https://registry.npmjs.org/reftools/-/reftools-1.1.9.tgz", - "integrity": "sha512-OVede/NQE13xBQ+ob5CKd5KyeJYU2YInb1bmV4nRoOfquZPkAkxuOXicSe1PvqIuZZ4kD13sPKBbR7UFDmli6w==", "license": "BSD-3-Clause", "funding": { "url": "https://github.com/Mermade/oas-kit?sponsor=1" @@ -5037,8 +4749,6 @@ }, "node_modules/regexp.prototype.flags": { "version": "1.5.4", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", - "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -5057,8 +4767,6 @@ }, "node_modules/require-directory": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -5066,38 +4774,76 @@ }, "node_modules/require-from-string": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/router": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", - "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "node_modules/ret": { + "version": "0.5.0", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "license": "MIT" + }, + "node_modules/rolldown": { + "version": "1.0.3", + "dev": true, "license": "MIT", "dependencies": { - "debug": "^4.4.0", - "depd": "^2.0.0", - "is-promise": "^4.0.0", - "parseurl": "^1.3.3", - "path-to-regexp": "^8.0.0" + "@oxc-project/types": "=0.133.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" }, "engines": { - "node": ">= 18" + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.3", + "@rolldown/binding-darwin-arm64": "1.0.3", + "@rolldown/binding-darwin-x64": "1.0.3", + "@rolldown/binding-freebsd-x64": "1.0.3", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.3", + "@rolldown/binding-linux-arm64-gnu": "1.0.3", + "@rolldown/binding-linux-arm64-musl": "1.0.3", + "@rolldown/binding-linux-ppc64-gnu": "1.0.3", + "@rolldown/binding-linux-s390x-gnu": "1.0.3", + "@rolldown/binding-linux-x64-gnu": "1.0.3", + "@rolldown/binding-linux-x64-musl": "1.0.3", + "@rolldown/binding-openharmony-arm64": "1.0.3", + "@rolldown/binding-wasm32-wasi": "1.0.3", + "@rolldown/binding-win32-arm64-msvc": "1.0.3", + "@rolldown/binding-win32-x64-msvc": "1.0.3" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" } }, "node_modules/safe-array-concat": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", - "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "version": "1.1.4", "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "get-intrinsic": "^1.3.0", "has-symbols": "^1.1.0", "isarray": "^2.0.5" }, @@ -5108,30 +4854,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-array-concat/node_modules/isarray": { + "version": "2.0.5", + "license": "MIT" + }, "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], + "version": "5.1.2", "license": "MIT" }, "node_modules/safe-push-apply": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", - "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -5144,10 +4876,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-push-apply/node_modules/isarray": { + "version": "2.0.5", + "license": "MIT" + }, "node_modules/safe-regex-test": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", - "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -5161,10 +4895,28 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-regex2": { + "version": "5.1.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "ret": "~0.5.0" + }, + "bin": { + "safe-regex2": "bin/safe-regex2.js" + } + }, "node_modules/safe-stable-stringify": { "version": "2.5.0", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", - "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", "license": "MIT", "engines": { "node": ">=10" @@ -5172,20 +4924,24 @@ }, "node_modules/safer-buffer": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, - "node_modules/scheduler": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", - "license": "MIT" + "node_modules/secure-json-parse": { + "version": "4.1.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" }, "node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "version": "7.8.1", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -5194,53 +4950,12 @@ "node": ">=10" } }, - "node_modules/send": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", - "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", - "license": "MIT", - "dependencies": { - "debug": "^4.3.5", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "mime-types": "^3.0.1", - "ms": "^2.1.3", - "on-finished": "^2.4.1", - "range-parser": "^1.2.1", - "statuses": "^2.0.1" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/serve-static": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", - "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", - "license": "MIT", - "dependencies": { - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "parseurl": "^1.3.3", - "send": "^1.2.0" - }, - "engines": { - "node": ">= 18" - } - }, "node_modules/set-cookie-parser": { "version": "2.7.2", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", - "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", "license": "MIT" }, "node_modules/set-function-length": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", @@ -5256,8 +4971,6 @@ }, "node_modules/set-function-name": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", - "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", @@ -5271,8 +4984,6 @@ }, "node_modules/set-proto": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", - "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", @@ -5285,26 +4996,10 @@ }, "node_modules/setimmediate": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "license": "MIT" - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "license": "ISC" - }, - "node_modules/shallowequal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", - "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", "license": "MIT" }, "node_modules/should": { "version": "13.2.3", - "resolved": "https://registry.npmjs.org/should/-/should-13.2.3.tgz", - "integrity": "sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==", "license": "MIT", "dependencies": { "should-equal": "^2.0.0", @@ -5316,8 +5011,6 @@ }, "node_modules/should-equal": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz", - "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==", "license": "MIT", "dependencies": { "should-type": "^1.4.0" @@ -5325,8 +5018,6 @@ }, "node_modules/should-format": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", - "integrity": "sha512-hZ58adtulAk0gKtua7QxevgUaXTTXxIi8t41L3zo9AHvjXO1/7sdLECuHeIN2SRtYXpNkmhoUP2pdeWgricQ+Q==", "license": "MIT", "dependencies": { "should-type": "^1.3.0", @@ -5335,14 +5026,10 @@ }, "node_modules/should-type": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", - "integrity": "sha512-MdAsTu3n25yDbIe1NeN69G4n6mUnJGtSJHygX3+oN0ZbO3DTiATnf7XnYJdGT42JCXurTb1JI0qOBR65shvhPQ==", "license": "MIT" }, "node_modules/should-type-adaptors": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz", - "integrity": "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==", "license": "MIT", "dependencies": { "should-type": "^1.3.0", @@ -5351,19 +5038,15 @@ }, "node_modules/should-util": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.1.tgz", - "integrity": "sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g==", "license": "MIT" }, "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "version": "1.1.1", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" }, @@ -5375,13 +5058,11 @@ } }, "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "version": "1.0.1", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" + "object-inspect": "^1.13.4" }, "engines": { "node": ">= 0.4" @@ -5392,8 +5073,6 @@ }, "node_modules/side-channel-map": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -5410,8 +5089,6 @@ }, "node_modules/side-channel-weakmap": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -5427,87 +5104,45 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/simple-websocket": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/simple-websocket/-/simple-websocket-9.1.0.tgz", - "integrity": "sha512-8MJPnjRN6A8UCp1I+H/dSFyjwJhp6wta4hsVRhjf8w9qBHRzxYt14RaOcjvQnhD1N4yKOddEjflwMnQM4VtXjQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "debug": "^4.3.1", - "queue-microtask": "^1.2.2", - "randombytes": "^2.1.0", - "readable-stream": "^3.6.0", - "ws": "^7.4.2" - } + "node_modules/siginfo": { + "version": "2.0.0", + "dev": true, + "license": "ISC" }, - "node_modules/slugify": { - "version": "1.4.7", - "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.4.7.tgz", - "integrity": "sha512-tf+h5W1IrjNm/9rKKj0JU2MDMruiopx0jjVA5zCdBtcGjfp0+c5rHw/zADLC3IeKlGHtVbHtpfzvYA0OYT+HKg==", + "node_modules/sonic-boom": { + "version": "4.2.1", "license": "MIT", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" + "dependencies": { + "atomic-sleep": "^1.0.0" } }, "node_modules/source-map-js": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, - "node_modules/stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", - "license": "MIT", + "node_modules/split2": { + "version": "4.2.0", + "license": "ISC", "engines": { - "node": "*" + "node": ">= 10.x" } }, - "node_modules/statuses": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } + "node_modules/stackback": { + "version": "0.0.2", + "dev": true, + "license": "MIT" }, - "node_modules/stickyfill": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stickyfill/-/stickyfill-1.1.1.tgz", - "integrity": "sha512-GCp7vHAfpao+Qh/3Flh9DXEJ/qSi0KJwJw6zYlZOtRYXWUIpMM6mC2rIep/dK8RQqwW0KxGJIllmjPIBOGN8AA==" + "node_modules/std-env": { + "version": "4.1.0", + "dev": true, + "license": "MIT" }, "node_modules/stop-iteration-iterator": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", - "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -5517,27 +5152,15 @@ "node": ">= 0.4" } }, - "node_modules/streamsearch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", - "engines": { - "node": ">=10.0.0" - } - }, "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "version": "1.1.1", "license": "MIT", "dependencies": { - "safe-buffer": "~5.2.0" + "safe-buffer": "~5.1.0" } }, "node_modules/string-width": { "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -5549,18 +5172,17 @@ } }, "node_modules/string.prototype.trim": { - "version": "1.2.10", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", - "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "version": "1.2.11", "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", "define-data-property": "^1.1.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-object-atoms": "^1.0.0", - "has-property-descriptors": "^1.0.2" + "define-properties": "^1.2.1", + "es-abstract": "^1.24.2", + "es-object-atoms": "^1.1.2", + "has-property-descriptors": "^1.0.2", + "safe-regex-test": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -5570,15 +5192,13 @@ } }, "node_modules/string.prototype.trimend": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", - "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "version": "1.0.10", "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" + "es-object-atoms": "^1.1.2" }, "engines": { "node": ">= 0.4" @@ -5589,8 +5209,6 @@ }, "node_modules/string.prototype.trimstart": { "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", - "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "license": "MIT", "dependencies": { "call-bind": "^1.0.7", @@ -5606,8 +5224,6 @@ }, "node_modules/strip-ansi": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -5617,66 +5233,34 @@ } }, "node_modules/strnum": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.2.0.tgz", - "integrity": "sha512-Y7Bj8XyJxnPAORMZj/xltsfo55uOiyHcU2tnAVzHUnSJR/KsEX+9RoDeXEnsXtl/CX4fAcrt64gZ13aGaWPeBg==", + "version": "2.4.0", "funding": [ { "type": "github", "url": "https://github.com/sponsors/NaturalIntelligence" } ], - "license": "MIT" + "license": "MIT", + "dependencies": { + "anynum": "^1.0.0" + } }, - "node_modules/styled-components": { - "version": "6.3.9", - "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.3.9.tgz", - "integrity": "sha512-J72R4ltw0UBVUlEjTzI0gg2STOqlI9JBhQOL4Dxt7aJOnnSesy0qJDn4PYfMCafk9cWOaVg129Pesl5o+DIh0Q==", + "node_modules/strtok3": { + "version": "10.3.5", "license": "MIT", "dependencies": { - "@emotion/is-prop-valid": "1.4.0", - "@emotion/unitless": "0.10.0", - "@types/stylis": "4.2.7", - "css-to-react-native": "3.2.0", - "csstype": "3.2.3", - "postcss": "8.4.49", - "shallowequal": "1.1.0", - "stylis": "4.3.6", - "tslib": "2.8.1" + "@tokenizer/token": "^0.3.0" }, "engines": { - "node": ">= 16" + "node": ">=18" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/styled-components" - }, - "peerDependencies": { - "react": ">= 16.8.0", - "react-dom": ">= 16.8.0" - }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - } + "type": "github", + "url": "https://github.com/sponsors/Borewit" } }, - "node_modules/styled-components/node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, - "node_modules/stylis": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.6.tgz", - "integrity": "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==", - "license": "MIT" - }, "node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -5687,8 +5271,6 @@ }, "node_modules/swagger2openapi": { "version": "7.0.8", - "resolved": "https://registry.npmjs.org/swagger2openapi/-/swagger2openapi-7.0.8.tgz", - "integrity": "sha512-upi/0ZGkYgEcLeGieoz8gT74oWHA0E7JivX7aN9mAf+Tc7BQoRBvnIGHoPDw+f9TXTW4s6kGYCZJtauP6OYp7g==", "license": "BSD-3-Clause", "dependencies": { "call-me-maybe": "^1.0.1", @@ -5712,66 +5294,110 @@ "url": "https://github.com/Mermade/oas-kit?sponsor=1" } }, - "node_modules/text-hex": { + "node_modules/thread-stream": { + "version": "4.2.0", + "license": "MIT", + "dependencies": { + "real-require": "^1.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/thread-stream/node_modules/real-require": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", - "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", "license": "MIT" }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "node_modules/tinybench": { + "version": "2.9.0", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.2.4", + "dev": true, "license": "MIT", "engines": { - "node": ">=0.6" + "node": ">=18" } }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "license": "MIT" + "node_modules/tinyglobby": { + "version": "0.2.17", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } }, - "node_modules/triple-beam": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", - "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "node_modules/tinyrainbow": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/toad-cache": { + "version": "3.7.1", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/token-types": { + "version": "6.1.2", "license": "MIT", + "dependencies": { + "@borewit/text-codec": "^0.2.1", + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" + }, "engines": { - "node": ">= 14.0.0" + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" } }, + "node_modules/tr46": { + "version": "0.0.3", + "license": "MIT" + }, "node_modules/ts-algebra": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-1.2.2.tgz", - "integrity": "sha512-kloPhf1hq3JbCPOTYoOWDKxebWjNb2o/LKnNfkWhxVVisFFmMJPPdJeGoGmM+iRLyoXAR61e08Pb+vUXINg8aA==", "license": "MIT" }, "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "version": "2.8.1", "license": "0BSD" }, - "node_modules/type-is": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", - "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "node_modules/tsx": { + "version": "4.22.4", + "dev": true, "license": "MIT", "dependencies": { - "content-type": "^1.0.5", - "media-typer": "^1.1.0", - "mime-types": "^3.0.0" + "esbuild": "~0.28.0" + }, + "bin": { + "tsx": "dist/cli.mjs" }, "engines": { - "node": ">= 0.6" + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" } }, "node_modules/typed-array-buffer": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", - "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -5784,8 +5410,6 @@ }, "node_modules/typed-array-byte-length": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", - "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -5803,8 +5427,6 @@ }, "node_modules/typed-array-byte-offset": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", - "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", @@ -5823,17 +5445,15 @@ } }, "node_modules/typed-array-length": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", - "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "version": "1.0.8", "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0", - "reflect.getprototypeof": "^1.0.6" + "call-bind": "^1.0.9", + "for-each": "^0.3.5", + "gopd": "^1.2.0", + "is-typed-array": "^1.1.15", + "possible-typed-array-names": "^1.1.0", + "reflect.getprototypeof": "^1.0.10" }, "engines": { "node": ">= 0.4" @@ -5842,51 +5462,40 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", - "license": "MIT" - }, "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "version": "6.0.3", + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" } }, - "node_modules/uglify-js": { - "version": "3.19.3", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", - "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", - "license": "BSD-2-Clause", - "optional": true, - "bin": { - "uglifyjs": "bin/uglifyjs" + "node_modules/uid": { + "version": "2.0.2", + "license": "MIT", + "dependencies": { + "@lukeed/csprng": "^1.0.0" }, "engines": { - "node": ">=0.8.0" + "node": ">=8" } }, - "node_modules/ulid": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/ulid/-/ulid-3.0.2.tgz", - "integrity": "sha512-yu26mwteFYzBAot7KVMqFGCVpsF6g8wXfJzQUHvu1no3+rRRSFcSV2nKeYvNPLD2J4b08jYBDhHUjeH0ygIl9w==", + "node_modules/uint8array-extras": { + "version": "1.5.0", "license": "MIT", - "bin": { - "ulid": "dist/cli.js" + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/unbox-primitive": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", - "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -5901,127 +5510,229 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/undici": { - "version": "6.24.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.24.0.tgz", - "integrity": "sha512-lVLNosgqo5EkGqh5XUDhGfsMSoO8K0BAN0TyJLvwNRSl4xWGZlCVYsAIpa/OpA3TvmnM01GWcoKmc3ZWo5wKKA==", - "license": "MIT", - "engines": { - "node": ">=18.17" - } - }, "node_modules/undici-types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "version": "7.24.6", "license": "MIT" }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/urijs": { "version": "1.19.11", - "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz", - "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==", "license": "MIT" }, - "node_modules/url-template": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", - "integrity": "sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw==", - "license": "BSD" - }, - "node_modules/use-sync-external-store": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", - "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", - "license": "MIT", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, "node_modules/util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, "node_modules/utility-types": { "version": "3.11.0", - "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz", - "integrity": "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==", "license": "MIT", "engines": { "node": ">= 4" } }, "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "version": "14.0.0", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], "license": "MIT", "bin": { - "uuid": "dist/bin/uuid" + "uuid": "dist-node/bin/uuid" } }, "node_modules/validate.io-array": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/validate.io-array/-/validate.io-array-1.0.6.tgz", - "integrity": "sha512-DeOy7CnPEziggrOO5CZhVKJw6S3Yi7e9e65R1Nl/RTN1vTQKnzjfvks0/8kQ40FP/dsjRAOd4hxmJ7uLa6vxkg==", "license": "MIT" }, "node_modules/validate.io-function": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/validate.io-function/-/validate.io-function-1.0.2.tgz", - "integrity": "sha512-LlFybRJEriSuBnUhQyG5bwglhh50EpTL2ul23MPIuR1odjO7XaMLFV8vHGwp7AZciFxtYOeiSCT5st+XSPONiQ==" + "version": "1.0.2" }, "node_modules/validate.io-integer": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/validate.io-integer/-/validate.io-integer-1.0.5.tgz", - "integrity": "sha512-22izsYSLojN/P6bppBqhgUDjCkr5RY2jd+N2a3DCAUey8ydvrZ/OkGvFPR7qfOpwR2LC5p4Ngzxz36g5Vgr/hQ==", "dependencies": { "validate.io-number": "^1.0.3" } }, "node_modules/validate.io-integer-array": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/validate.io-integer-array/-/validate.io-integer-array-1.0.0.tgz", - "integrity": "sha512-mTrMk/1ytQHtCY0oNO3dztafHYyGU88KL+jRxWuzfOmQb+4qqnWmI+gykvGp8usKZOM0H7keJHEbRaFiYA0VrA==", "dependencies": { "validate.io-array": "^1.0.3", "validate.io-integer": "^1.0.4" } }, "node_modules/validate.io-number": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/validate.io-number/-/validate.io-number-1.0.3.tgz", - "integrity": "sha512-kRAyotcbNaSYoDnXvb4MHg/0a1egJdLwS6oJ38TJY7aw9n93Fl/3blIXdyYvPOp55CNxywooG/3BcrwNrBpcSg==" + "version": "1.0.3" }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "node_modules/vite": { + "version": "8.0.16", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.15", + "rolldown": "1.0.3", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.18", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vitest": { + "version": "4.1.8", + "dev": true, "license": "MIT", + "dependencies": { + "@vitest/expect": "4.1.8", + "@vitest/mocker": "4.1.8", + "@vitest/pretty-format": "4.1.8", + "@vitest/runner": "4.1.8", + "@vitest/snapshot": "4.1.8", + "@vitest/spy": "4.1.8", + "@vitest/utils": "4.1.8", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^4.0.0-rc.1", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, "engines": { - "node": ">= 0.8" + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.1.8", + "@vitest/browser-preview": "4.1.8", + "@vitest/browser-webdriverio": "4.1.8", + "@vitest/coverage-istanbul": "4.1.8", + "@vitest/coverage-v8": "4.1.8", + "@vitest/ui": "4.1.8", + "happy-dom": "*", + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } } }, "node_modules/webidl-conversions": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", "license": "BSD-2-Clause" }, "node_modules/whatwg-url": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "license": "MIT", "dependencies": { "tr46": "~0.0.3", @@ -6030,8 +5741,6 @@ }, "node_modules/which-boxed-primitive": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", - "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", "license": "MIT", "dependencies": { "is-bigint": "^1.1.0", @@ -6049,8 +5758,6 @@ }, "node_modules/which-builtin-type": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", - "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -6074,10 +5781,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/which-builtin-type/node_modules/isarray": { + "version": "2.0.5", + "license": "MIT" + }, "node_modules/which-collection": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", - "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", "license": "MIT", "dependencies": { "is-map": "^2.0.3", @@ -6093,13 +5802,11 @@ } }, "node_modules/which-typed-array": { - "version": "1.1.19", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", - "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "version": "1.1.22", "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", + "call-bind": "^1.0.9", "call-bound": "^1.0.4", "for-each": "^0.3.5", "get-proto": "^1.0.1", @@ -6113,52 +5820,23 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/winston": { - "version": "3.19.0", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.19.0.tgz", - "integrity": "sha512-LZNJgPzfKR+/J3cHkxcpHKpKKvGfDZVPS4hfJCc4cCG0CgYzvlD6yE/S3CIL/Yt91ak327YCpiF/0MyeZHEHKA==", + "node_modules/why-is-node-running": { + "version": "2.3.0", + "dev": true, "license": "MIT", "dependencies": { - "@colors/colors": "^1.6.0", - "@dabh/diagnostics": "^2.0.8", - "async": "^3.2.3", - "is-stream": "^2.0.0", - "logform": "^2.7.0", - "one-time": "^1.0.0", - "readable-stream": "^3.4.0", - "safe-stable-stringify": "^2.3.1", - "stack-trace": "0.0.x", - "triple-beam": "^1.3.0", - "winston-transport": "^4.9.0" + "siginfo": "^2.0.0", + "stackback": "0.0.2" }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/winston-transport": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", - "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==", - "license": "MIT", - "dependencies": { - "logform": "^2.7.0", - "readable-stream": "^3.6.2", - "triple-beam": "^1.3.0" + "bin": { + "why-is-node-running": "cli.js" }, "engines": { - "node": ">= 12.0.0" + "node": ">=8" } }, - "node_modules/wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "license": "MIT" - }, "node_modules/wrap-ansi": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -6172,70 +5850,45 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" - }, - "node_modules/ws": { - "version": "7.5.10", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", - "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", - "license": "MIT", - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true + "node_modules/xml-naming": { + "version": "0.1.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" } - } - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + ], "license": "MIT", "engines": { - "node": ">=0.4" + "node": ">=16.0.0" } }, "node_modules/y18n": { "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "license": "ISC", "engines": { "node": ">=10" } }, "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "version": "2.9.0", "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, "engines": { - "node": ">= 6" + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" } }, "node_modules/yaml-ast-parser": { "version": "0.0.43", - "resolved": "https://registry.npmjs.org/yaml-ast-parser/-/yaml-ast-parser-0.0.43.tgz", - "integrity": "sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==", "license": "Apache-2.0" }, "node_modules/yargs": { "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "license": "MIT", "dependencies": { "cliui": "^8.0.1", @@ -6252,8 +5905,6 @@ }, "node_modules/yargs-parser": { "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "license": "ISC", "engines": { "node": ">=12" diff --git a/package.json b/package.json index e81c54c..efce107 100644 --- a/package.json +++ b/package.json @@ -2,36 +2,46 @@ "name": "tools-api-v1", "version": "1.0.0", "description": "API van het Tools (apis.developer.overheid.nl)", - "main": "index.js", + "main": "dist/app/index.js", "scripts": { - "prestart": "npm install", - "start": "node index.js", - "start-mock": "USE_MOCKS=true node index.js", - "test": "node --test", + "init-install": "npm install", + "dev": "tsx watch --env-file=.env app/index.ts", + "dev-mock": "OPENAPI_MOCK=true npm run dev", + "prebuild": "rm -rf dist", + "build": "tsc", + "start": "node --env-file-if-exists=.env dist/app/index.js", + "test": "vitest run", "lint": "biome lint .", - "format": "biome format --write ." + "format": "biome format --write .", + "typecheck": "tsc --noEmit" }, "license": "EUPL-1.2", "private": true, "dependencies": { - "@apiture/openapi-down-convert": "^0.14.2", - "@developer-overheid-nl/adr-rulesets": "github:developer-overheid-nl/adr-rulesets#da1327dfcc83ed130b1fe5aaa282b7bfba537aee", - "@redocly/cli": "^2.30.3", - "@scalar/openapi-upgrader": "^0.2.7", - "@stoplight/spectral-parsers": "^1.0.5", - "@stoplight/spectral-rulesets": "^1.22.1", - "@stoplight/spectral-runtime": "^1.1.5", - "body-parser": "^2.2.2", - "case-anything": "^3.1.2", - "cors": "^2.8.6", - "express": "^5.2.1", - "express-openapi-validator": "^5.6.2", - "js-yaml": "^4.1.1", - "jszip": "^3.10.1", - "openapi-to-postmanv2": "^6.0.1", - "winston": "^3.19.0" + "@developer-overheid-nl/don-tools-logic": "^0.0.1", + "@fastify/cors": "^11.2.0", + "@nestjs/common": "^11.0.0", + "@nestjs/core": "^11.0.0", + "@nestjs/platform-fastify": "^11.0.0", + "ajv-formats": "^3.0.1", + "fastify": "^5.8.5", + "js-yaml": "^4.2.0", + "openapi-backend": "^5.17.0", + "reflect-metadata": "^0.2.2", + "rxjs": "^7.8.1" }, "devDependencies": { - "@biomejs/biome": "^2.4.13" + "@biomejs/biome": "^2.4.16", + "@types/node": "^25.9.2", + "tsx": "^4.22.4", + "typescript": "^6.0.3", + "vite": "^8.0.16", + "vitest": "^4.1.8" + }, + "overrides": { + "js-yaml@>=4.0.0 <4.1.1": "4.2.0", + "lodash@<=4.17.23": "4.18.1", + "uuid@<11.1.1": "14.0.0", + "yaml@>=1.0.0 <1.10.3": "2.9.0" } } diff --git a/publiccode.yml b/publiccode.yml index 34ba177..4972657 100644 --- a/publiccode.yml +++ b/publiccode.yml @@ -26,9 +26,9 @@ description: Ontwikkelaars kunnen via deze API OpenAPI-specificaties omzetten tussen versies (3.0 en 3.1), specificaties bundelen, valideren tegen de DON API Design Rules (ADR) ruleset, Postman-collecties genereren en - Arazzo-workflows visualiseren. De API is gebouwd met Node.js en Express - en volgt een API-first aanpak waarbij het OpenAPI-contract leidend is - voor de implementatie. + Arazzo-workflows visualiseren. De API is gebouwd met Node.js, + TypeScript en Fastify en volgt een API-first aanpak waarbij het + OpenAPI-contract leidend is voor de implementatie. features: - OpenAPI specificatie conversie tussen versie 3.0 en 3.1 - OpenAPI specificatie bundeling met oplossen van externe verwijzingen diff --git a/services/ArazzoVisualizationService.js b/services/ArazzoVisualizationService.js deleted file mode 100644 index 726a318..0000000 --- a/services/ArazzoVisualizationService.js +++ /dev/null @@ -1,749 +0,0 @@ -"use strict"; - -const fs = require("node:fs/promises"); -const path = require("node:path"); -const os = require("node:os"); -const jsYaml = require("js-yaml"); -const { - logger: redoclyLogger, - createConfig, - lint, - bundle, - getTotals, - formatProblems, -} = require("@redocly/openapi-core"); -const Service = require("./Service"); -const { fetchSpecification } = require("./RemoteSpecificationService"); -const { resolveOasInput } = require("./OasInputService"); -const appLogger = require("../logger"); - -// --------------------------------------------------------------------------- -// Constante waarden / config -// --------------------------------------------------------------------------- - -const EMPTY_BODY_ERROR = "Body ontbreekt of ongeldig: gebruik oasUrl|oasBody"; -const INVALID_SPEC_ERROR = "Arazzo specificatie ongeldig of mist workflows"; -const TEMP_PREFIX = "don-tools-arazzo-"; - -const SOURCE_REF_PREFIX = "$sourceDescriptions."; -const COMPONENT_INPUTS_PREFIX = "#/components/inputs/"; -const ALLOWED_METHODS = Object.freeze( - new Set(["get", "put", "post", "delete", "patch", "head", "options", "trace"]), -); - -let redoclyConfigPromise; -let arazzoLintConfigPromise; - -const getRedoclyConfig = () => { - if (!redoclyConfigPromise) { - redoclyConfigPromise = createConfig({ extends: ["recommended"] }); - } - return redoclyConfigPromise; -}; - -const getArazzoLintConfig = () => { - if (!arazzoLintConfigPromise) { - arazzoLintConfigPromise = createConfig({ - extends: ["recommended-strict"], - arazzo1Rules: { - "no-criteria-xpath": "error", - "respect-supported-versions": "warn", - "no-x-security-scheme-name-without-openapi": "error", - "x-security-scheme-required-values": "error", - "x-security-scheme-name-reference": "error", - "no-x-security-both-scheme-and-scheme-name": "error", - }, - }); - } - return arazzoLintConfigPromise; -}; - -const isLikelyArazzoTestFile = (fileName, parsedDocument) => { - if (!fileName || typeof fileName !== "string") return false; - return /\.(yaml|yml|json)$/i.test(fileName) && !!parsedDocument?.arazzo; -}; - -const logLintSummary = (lintProblems, version) => { - if (!Array.isArray(lintProblems) || lintProblems.length === 0) { - return; - } - - const totals = getTotals(lintProblems); - formatProblems(lintProblems, { totals, version }); - - if (totals.errors > 0) { - appLogger.error("[ArazzoService] lint errors in Arazzo beschrijving", { errors: totals.errors }); - } else if (totals.warnings > 0) { - appLogger.warn("[ArazzoService] lint waarschuwingen in Arazzo beschrijving", { warnings: totals.warnings }); - } -}; - -const bundleArazzoDocument = async ({ - filePath, - base, - externalRefResolver, - collectSpecData, - version = "don-tools-api", - skipLint = false, -}) => { - const fileName = path.basename(filePath); - if (!fileName) { - throw new Error("Invalid file name"); - } - - const config = await getArazzoLintConfig(); - let lintProblems = []; - - if (!skipLint) { - lintProblems = await lint({ - ref: filePath, - config, - externalRefResolver, - }); - - logLintSummary(lintProblems, version); - } - - const bundledDocument = await bundle({ - base, - ref: filePath, - config, - dereference: true, - externalRefResolver, - }); - - const parsedDocument = bundledDocument?.bundle?.parsed; - - if (!parsedDocument) { - throw new Error(`Could not find source description file '${fileName}'.`); - } - - if (!isLikelyArazzoTestFile(fileName, parsedDocument)) { - throw new Error( - `No test files found. File ${fileName} voldoet niet aan het patroon "*.[yaml|yml|json]" of mist een geldige "Arazzo" beschrijving.`, - ); - } - - collectSpecData?.(parsedDocument); - - if (!skipLint) { - const errors = lintProblems.filter((problem) => problem.severity === "error"); - if (errors.length > 0) { - throw new Error(`Found errors in Arazzo description ${fileName}.`); - } - } - - return parsedDocument; -}; - -// --------------------------------------------------------------------------- -// Helpers: I/O & parsing -// --------------------------------------------------------------------------- - -const normalizeText = (value) => { - if (!value || typeof value !== "string") return ""; - return value.trim(); -}; - -const ensureTempFile = async (contents, filename = "input.yaml") => { - const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), TEMP_PREFIX)); - const filePath = path.join(tempDir, filename); - - await fs.writeFile(filePath, contents, "utf8"); - - const cleanup = async () => { - try { - await fs.rm(tempDir, { recursive: true, force: true }); - } catch (error) { - appLogger.warn("[ArazzoService] opruimen temp dir faalde", { - tempDir, - message: error?.message, - }); - } - }; - - return { filePath, cleanup }; -}; - -const parseYamlOrUndefined = (contents) => { - try { - const parsed = jsYaml.load(contents); - return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : undefined; - } catch { - return undefined; - } -}; - -// --------------------------------------------------------------------------- -// Input normalisatie (body / URL / oas*) -// --------------------------------------------------------------------------- - -/** - * Normaliseert de input naar `{ source, contents }`. - * Ondersteunt: - * - `arazzoBody` (string) - * - `arazzoUrl` (URL) - * - fallback naar `resolveOasInput` (oasUrl/oasBody/etc.) - */ -const resolveVisualizationInput = async (input) => { - if (!input || typeof input !== "object") { - throw Service.rejectResponse({ message: EMPTY_BODY_ERROR }, 400); - } - - const { arazzoBody, arazzoUrl } = input; - - // 1) Directe Arazzo-body - if (typeof arazzoBody === "string" && arazzoBody.trim().length > 0) { - return { - source: "request-body", - contents: arazzoBody, - }; - } - - // 2) Arazzo-URL - if (typeof arazzoUrl === "string" && arazzoUrl.trim().length > 0) { - let parsedUrl; - try { - parsedUrl = new URL(arazzoUrl); - } catch { - throw Service.rejectResponse( - { - message: "De waarde van arazzoUrl is geen geldige URL.", - }, - 400, - ); - } - - const contents = await fetchSpecification(parsedUrl.toString(), { - errorMessage: "Het ophalen van de Arazzo specificatie is mislukt.", - }); - - return { - source: parsedUrl.toString(), - contents, - }; - } - - // 3) Fallback: dit beschouwen we als OpenAPI input (oasUrl/oasBody/etc.) - const resolved = await resolveOasInput(input); - const trimmed = typeof resolved.contents === "string" ? resolved.contents.trim() : ""; - - if (!trimmed) { - throw Service.rejectResponse({ message: EMPTY_BODY_ERROR }, 400); - } - - return { - source: resolved.source, - contents: trimmed, - }; -}; - -// --------------------------------------------------------------------------- -// Arazzo-document ophalen / genereren -// --------------------------------------------------------------------------- - -/** - * Bundelt een Arazzo-document vanuit YAML/JSON met respect-core (bundleArazzo). - */ -const loadArazzoDocumentFromContents = async (contents) => { - const { filePath, cleanup } = await ensureTempFile(contents, "arazzo.yaml"); - - try { - const document = await bundleArazzoDocument({ - filePath, - base: path.dirname(filePath), - externalRefResolver: undefined, - collectSpecData: undefined, - version: "don-tools-api", - skipLint: true, - }); - - if (!document || !Array.isArray(document.workflows) || document.workflows.length === 0) { - throw new Error(INVALID_SPEC_ERROR); - } - - return document; - } catch (error) { - appLogger.error("[ArazzoService] bundelen Arazzo-document mislukt", { - message: error?.message, - detail: error?.detail, - stack: error?.stack, - }); - throw error; - } finally { - await cleanup(); - } -}; - -/** - * Genereert Arazzo-workflows vanuit een OpenAPI-spec via respect-core (generate). - */ -const generateArazzoFromOpenApi = async (contents) => { - const { filePath, cleanup } = await ensureTempFile(contents, "openapi.yaml"); - - try { - const { generate } = await import("@redocly/respect-core"); - const config = await getRedoclyConfig(); - - const document = await generate({ - descriptionPath: filePath, - collectSpecData: undefined, - version: "don-tools-api", - config, - base: path.dirname(filePath), - }); - - if (!document || !Array.isArray(document.workflows) || document.workflows.length === 0) { - throw new Error(INVALID_SPEC_ERROR); - } - - return document; - } catch (error) { - appLogger.error("[ArazzoService] generate from OpenAPI failed", { - message: error?.message, - stack: error?.stack, - }); - - throw Service.rejectResponse( - { - message: "Kon Arazzo workflows genereren vanuit OpenAPI.", - detail: error.message, - }, - 400, - ); - } finally { - await cleanup(); - } -}; - -// --------------------------------------------------------------------------- -// OpenAPI helpers (operation lookup / schema beschrijving) -// --------------------------------------------------------------------------- - -const buildOperationLookup = (openapiDocument) => { - const lookup = new Map(); - - if (!openapiDocument || typeof openapiDocument !== "object") return lookup; - - const { paths } = openapiDocument; - if (!paths || typeof paths !== "object") return lookup; - - Object.entries(paths).forEach(([pathKey, pathItem]) => { - if (!pathItem || typeof pathItem !== "object") return; - - Object.entries(pathItem).forEach(([method, operation]) => { - if (!ALLOWED_METHODS.has(method) || !operation || typeof operation !== "object") return; - - const { operationId } = operation; - if (!operationId) return; - - lookup.set(operationId, { - method: method.toUpperCase(), - path: pathKey, - summary: normalizeText(operation.summary), - description: normalizeText(operation.description), - tags: Array.isArray(operation.tags) ? operation.tags : undefined, - }); - }); - }); - - return lookup; -}; - -const describeSchemaType = (schema) => { - if (!schema || typeof schema !== "object") return ""; - - const parts = []; - - if (schema.type) { - parts.push(schema.type + (schema.format ? ` (${schema.format})` : "")); - } else if (schema.format) { - parts.push(schema.format); - } - - if (schema.enum) { - parts.push(`mogelijk: ${schema.enum.join(", ")}`); - } - - return parts.join(" | "); -}; - -const formatInputDefinition = (name, schema) => { - const lines = [`- **${name}**`]; - const description = normalizeText(schema?.description); - const typeInfo = describeSchemaType(schema); - - if (description || typeInfo) { - const details = [description, typeInfo ? `type: ${typeInfo}` : undefined] - .filter(Boolean) - .join(" | "); - lines.push(` - ${details}`); - } - - if (schema && typeof schema === "object" && schema.properties && typeof schema.properties === "object") { - lines.push(" - Velden:"); - Object.entries(schema.properties).forEach(([propName, propSchema]) => { - const propType = describeSchemaType(propSchema); - const propDescription = normalizeText(propSchema?.description); - const suffix = [propType, propDescription].filter(Boolean).join(" — "); - lines.push(` - ${propName}${suffix ? ` — ${suffix}` : ""}`); - }); - } - - return lines; -}; - -const resolveInputs = (inputs, components) => { - if (!inputs) return []; - - // $ref naar #/components/inputs/* - if (inputs.$ref && typeof inputs.$ref === "string") { - if (!inputs.$ref.startsWith(COMPONENT_INPUTS_PREFIX)) return []; - - const refName = inputs.$ref.slice(COMPONENT_INPUTS_PREFIX.length); - const definition = components?.[refName]; - if (!definition) return []; - - return [{ name: refName, schema: definition }]; - } - - // Inline definitie - if (typeof inputs === "object") { - const inlineName = inputs.name || inputs.title || "inputs"; - return [{ name: inlineName, schema: inputs }]; - } - - return []; -}; - -const formatParameterValue = (value) => { - if (typeof value === "string") return value; - if (value === undefined) return "onbekend"; - return JSON.stringify(value); -}; - -const appendCriteriaLines = (lines, items, label) => { - if (!Array.isArray(items) || items.length === 0) return; - - lines.push(` - ${label}:`); - items.forEach((criteria) => { - const condition = normalizeText(criteria?.condition) || "(geen conditie)"; - const detail = normalizeText(criteria?.description); - lines.push(` - ${condition}${detail ? ` — ${detail}` : ""}`); - }); -}; - -const appendOutputs = (lines, outputs) => { - if (!outputs || typeof outputs !== "object" || Object.keys(outputs).length === 0) return; - - lines.push(" - Outputs:"); - Object.entries(outputs).forEach(([key, value]) => { - lines.push(` - ${key}: ${JSON.stringify(value)}`); - }); -}; - -const parseStepOperation = (value) => { - if (!value || typeof value !== "string") { - return { raw: "", operationId: "" }; - } - - if (!value.startsWith(SOURCE_REF_PREFIX)) { - return { raw: value, operationId: value }; - } - - const remainder = value.slice(SOURCE_REF_PREFIX.length); - const delimiterIndex = remainder.indexOf("."); - - if (delimiterIndex === -1) { - return { raw: value, operationId: remainder }; - } - - return { - raw: value, - source: remainder.slice(0, delimiterIndex), - operationId: remainder.slice(delimiterIndex + 1), - }; -}; - -const describeStepOperation = (step, operationLookup) => { - const parsedOperation = parseStepOperation(step.operationId); - const operationDetails = parsedOperation.operationId ? operationLookup.get(parsedOperation.operationId) : undefined; - - const suffixParts = []; - - if (operationDetails?.method && operationDetails.path) { - suffixParts.push(`${operationDetails.method} ${operationDetails.path}`); - } - - if (parsedOperation.operationId) { - suffixParts.push(parsedOperation.operationId); - } - - const suffix = suffixParts.length > 0 ? ` (${suffixParts.join(" · ")})` : ""; - - return { parsedOperation, operationDetails, suffix }; -}; - -// --------------------------------------------------------------------------- -// Markdown output -// --------------------------------------------------------------------------- - -const buildMarkdown = (document, options = {}) => { - const lines = []; - const title = normalizeText(document.info?.title) || "Arazzo Workflows"; - const description = normalizeText(document.info?.description); - const operationLookup = buildOperationLookup(options.openapi); - - lines.push(`# ${title}`); - if (description) { - lines.push("", description); - } - - (document.workflows || []).forEach((workflow, workflowIndex) => { - const workflowTitle = - normalizeText(workflow.summary) || workflow.workflowId || `Workflow ${workflowIndex + 1}`; - - lines.push("", `## ${workflowTitle}`); - - if (workflow.description) { - lines.push("", workflow.description.trim()); - } - - // Inputs - const inputs = resolveInputs(workflow.inputs, document.components?.inputs); - if (inputs.length > 0) { - lines.push("", "### Inputs"); - inputs.forEach((input) => { - formatInputDefinition(input.name, input.schema).forEach((line) => { - lines.push(line); - }); - }); - } - - // Parameters - if (Array.isArray(workflow.parameters) && workflow.parameters.length > 0) { - lines.push("", "### Parameters"); - workflow.parameters.forEach((parameter) => { - const location = parameter.in || "parameter"; - const name = parameter.name || "naamloos"; - const value = formatParameterValue(parameter.value); - - lines.push(`- ${name} (${location}) = ${value}`); - if (parameter.description) { - lines.push(` - ${parameter.description.trim()}`); - } - }); - } - - // Steps - if (Array.isArray(workflow.steps) && workflow.steps.length > 0) { - lines.push("", "### Stappen"); - workflow.steps.forEach((step, index) => { - const stepLabel = step.stepId || `Stap ${index + 1}`; - const { operationDetails, suffix } = describeStepOperation(step, operationLookup); - - lines.push(`- **${stepLabel}${suffix}**`); - - const summary = operationDetails?.summary; - const descriptionText = operationDetails?.description; - - if (summary) { - lines.push(` - ${summary}`); - } - - if (descriptionText && descriptionText !== summary) { - lines.push(` - ${descriptionText}`); - } - - const stepDescription = normalizeText(step.description); - if ( - stepDescription && - stepDescription !== summary && - stepDescription !== descriptionText - ) { - lines.push(` - ${stepDescription}`); - } - - appendCriteriaLines(lines, step.successCriteria, "Succescriteria"); - appendCriteriaLines(lines, step.failureCriteria, "Faalcriteria"); - appendOutputs(lines, step.outputs); - }); - } - }); - - return lines.join("\n"); -}; - -// --------------------------------------------------------------------------- -// Mermaid output -// --------------------------------------------------------------------------- - -const escapeMermaidLabel = (value) => { - if (!value) return ""; - return String(value).replace(/"/g, '\\"'); -}; - -const sanitizeMermaidId = (value, fallback) => { - if (typeof value !== "string" || value.trim() === "") { - return fallback; - } - - const sanitized = value.replace(/[^a-zA-Z0-9_]/g, "_"); - if (!sanitized) { - return fallback; - } - - if (/^[0-9]/.test(sanitized)) { - return `S_${sanitized}`; - } - - return sanitized; -}; - -const buildMermaid = (document, options = {}) => { - const operationLookup = buildOperationLookup(options.openapi); - const lines = ["flowchart TD"]; - - (document.workflows || []).forEach((workflow, workflowIndex) => { - const workflowTitle = - normalizeText(workflow.summary) || workflow.workflowId || `Workflow ${workflowIndex + 1}`; - - lines.push("", `subgraph "${escapeMermaidLabel(workflowTitle)}"`); - - const steps = Array.isArray(workflow.steps) ? workflow.steps : []; - if (steps.length === 0) { - lines.push(' EmptyWorkflow["Geen stappen gedefinieerd"]'); - lines.push("end"); - return; - } - - const workflowKey = sanitizeMermaidId( - workflow.workflowId || `workflow_${workflowIndex + 1}`, - `workflow_${workflowIndex + 1}`, - ); - - const nodeIds = steps.map((step, index) => { - const stepKey = sanitizeMermaidId(step.stepId || `step_${index + 1}`, `step_${index + 1}`); - return `${workflowKey}_${stepKey}`; - }); - - steps.forEach((step, index) => { - const stepLabel = step.stepId || `Stap ${index + 1}`; - const { suffix } = describeStepOperation(step, operationLookup); - const label = escapeMermaidLabel(`${stepLabel}${suffix}`); - lines.push(` ${nodeIds[index]}["${label}"]`); - }); - - for (let i = 0; i < nodeIds.length - 1; i += 1) { - lines.push(` ${nodeIds[i]} --> ${nodeIds[i + 1]}`); - } - - lines.push("end"); - }); - - return lines.join("\n"); -}; - -// --------------------------------------------------------------------------- -// Conversie-functies: input -> Arazzo-document -// --------------------------------------------------------------------------- - -/** - * Hoofd-conversie: - * - Detecteert automatisch Arazzo vs OpenAPI. - * - Retourneert een Arazzo-document + optioneel het OpenAPI-document. - */ -const convertInputToArazzo = async (input) => { - const resolved = await resolveVisualizationInput(input); - - if (!resolved.contents || typeof resolved.contents !== "string" || !resolved.contents.trim()) { - throw Service.rejectResponse({ message: EMPTY_BODY_ERROR }, 400); - } - - const contents = resolved.contents; - const parsed = parseYamlOrUndefined(contents); - const isArazzoSpecification = Boolean(parsed && parsed.arazzo); - const openapiDocument = parsed && !isArazzoSpecification ? parsed : undefined; - - try { - const arazzoDocument = isArazzoSpecification - ? await loadArazzoDocumentFromContents(contents) - : await generateArazzoFromOpenApi(contents); - - return { - source: resolved.source, - arazzoDocument, - openapiDocument, - }; - } catch (error) { - if (Service.isErrorResponse && Service.isErrorResponse(error)) { - throw error; - } - - appLogger.error("[ArazzoService] Arazzo conversie mislukt", { - message: error?.message, - detail: error?.detail, - stack: error?.stack, - }); - - throw Service.rejectResponse( - { - message: error?.message && error.message !== "Unknown error" ? error.message : INVALID_SPEC_ERROR, - detail: error?.message, - }, - 400, - ); - } -}; - -const convertOasInputToArazzo = async (input) => { - const resolved = await resolveOasInput(input); - const contents = typeof resolved.contents === "string" ? resolved.contents.trim() : ""; - - if (!contents) { - throw Service.rejectResponse({ message: EMPTY_BODY_ERROR }, 400); - } - - const openapiDocument = parseYamlOrUndefined(contents) || undefined; - const arazzoDocument = await generateArazzoFromOpenApi(contents); - - return { - source: resolved.source, - arazzoDocument, - openapiDocument, - }; -}; - -// --------------------------------------------------------------------------- -// Publieke helpers: Arazzo-document -> Markdown / Mermaid -// --------------------------------------------------------------------------- - -const buildMarkdownFromArazzo = (arazzoDocument, { openapi } = {}) => - buildMarkdown(arazzoDocument, { openapi }); - -const buildMermaidFromArazzo = (arazzoDocument, { openapi } = {}) => - buildMermaid(arazzoDocument, { openapi }); - -// --------------------------------------------------------------------------- -// Hoofdfunctie: alles-in-één visualisatie -// --------------------------------------------------------------------------- - -/** - * Convenience: input (OAS of Arazzo) -> `{ markdown, mermaid }` - */ -const visualize = async (input) => { - const { arazzoDocument, openapiDocument } = await convertInputToArazzo(input); - - return { - markdown: buildMarkdownFromArazzo(arazzoDocument, { openapi: openapiDocument }), - mermaid: buildMermaidFromArazzo(arazzoDocument, { openapi: openapiDocument }), - }; -}; - -module.exports = { - visualize, - convertInputToArazzo, - convertOasInputToArazzo, - buildMarkdownFromArazzo, - buildMermaidFromArazzo, -}; diff --git a/services/KeycloakService.js b/services/KeycloakService.js deleted file mode 100644 index 659a80b..0000000 --- a/services/KeycloakService.js +++ /dev/null @@ -1,312 +0,0 @@ -const { randomUUID } = require("node:crypto"); -const { URL, URLSearchParams } = require("node:url"); -const Service = require("./Service"); - -const KEYCLOAK_CLIENT_DESCRIPTION = "Dit is een read-only api key. Meer info: https://apis.developer.overheid.nl/apis/toevoegen"; -const DEFAULT_TIMEOUT_MS = 30000; -const MAX_ERROR_BODY_LENGTH = 8192; - -const ERROR_CODES = { - CONFIG: "config", - CONFLICT: "conflict", - UNAUTHORIZED: "unauthorized", - CLIENT_ID_MISSING: "client_id_missing", - GENERIC: "generic", -}; - -class KeycloakError extends Error { - constructor(message, code = ERROR_CODES.GENERIC) { - super(message); - this.name = "KeycloakError"; - this.code = code; - } -} - -const resolveFetch = (fetchImpl) => { - if (typeof fetchImpl === "function") { - return fetchImpl; - } - if (typeof fetch === "function") { - return fetch; - } - throw new KeycloakError("Fetch API is niet beschikbaar in de huidige runtime.", ERROR_CODES.CONFIG); -}; - -const trimString = (value) => (typeof value === "string" ? value.trim() : ""); - -const truncate = (value, limit = MAX_ERROR_BODY_LENGTH) => { - if (typeof value !== "string") { - return ""; - } - if (value.length <= limit) { - return value; - } - return `${value.slice(0, limit)}…`; -}; - -const buildKeycloakPayload = (clientId, email) => { - const payload = { - clientId, - name: clientId, - enabled: true, - publicClient: true, - directAccessGrantsEnabled: false, - standardFlowEnabled: false, - serviceAccountsEnabled: false, - authorizationServicesEnabled: false, - protocol: "openid-connect", - description: KEYCLOAK_CLIENT_DESCRIPTION, - }; - - const attributes = {}; - if (email) { - attributes.email = email; - } - if (Object.keys(attributes).length > 0) { - payload.attributes = attributes; - } - return payload; -}; - -const extractClientIdFromLocation = (locationHeader) => { - const trimmed = trimString(locationHeader); - if (!trimmed) { - throw new KeycloakError("Keycloak response bevat geen Location header", ERROR_CODES.GENERIC); - } - - try { - const url = new URL(trimmed); - const candidate = trimString(url.pathname.split("/").pop()); - if (candidate) { - return candidate; - } - } catch { - // fall back to manual parsing - } - - const lastSlash = trimmed.lastIndexOf("/"); - if (lastSlash >= 0 && lastSlash < trimmed.length - 1) { - const candidate = trimString(trimmed.slice(lastSlash + 1)); - if (candidate) { - return candidate; - } - } - - throw new KeycloakError(`Kan clientId niet bepalen uit Keycloak Location header: ${trimmed}`, ERROR_CODES.GENERIC); -}; - -const buildUrlFromEnv = (baseUrl, realm, suffix) => { - const baseTrimmed = trimString(baseUrl).replace(/\/+$/, ""); - const realmTrimmed = trimString(realm); - if (!baseTrimmed || !realmTrimmed) { - return ""; - } - return `${baseTrimmed}${suffix}${encodeURIComponent(realmTrimmed)}`; -}; - -const createTimeoutSignal = (timeoutMs) => { - if (typeof AbortSignal !== "undefined" && typeof AbortSignal.timeout === "function") { - return { - signal: AbortSignal.timeout(timeoutMs), - cleanup: () => {}, - }; - } - const controller = new AbortController(); - const timeoutId = setTimeout(() => controller.abort(), timeoutMs); - const cleanup = () => clearTimeout(timeoutId); - return { - signal: controller.signal, - cleanup, - }; -}; - -const parseUntrustClientInput = (params) => { - const payload = Service.extractRequestBody(params); - if (!payload || typeof payload !== "object") { - Service.throwHttpError(400, "body ontbreekt"); - } - const email = typeof payload.email === "string" ? payload.email.trim() : ""; - if (!email) { - Service.throwHttpError(400, "email is verplicht"); - } - return { email }; -}; - -const translateKeycloakError = (error) => { - if (!(error instanceof KeycloakError)) { - return null; - } - switch (error.code) { - case ERROR_CODES.CONFIG: - return { status: 500, message: "Keycloak configuratie ontbreekt" }; - case ERROR_CODES.CONFLICT: - return { status: 409, message: "Keycloak client bestaat al" }; - case ERROR_CODES.UNAUTHORIZED: - return { status: 403, message: "Geen toegang tot Keycloak admin API" }; - case ERROR_CODES.CLIENT_ID_MISSING: - return { status: 400, message: "clientId ontbreekt of is ongeldig" }; - default: - return { status: 500, message: error.message || "Er is een fout opgetreden bij Keycloak." }; - } -}; - -class KeycloakService { - constructor({ - adminClientsURL = "", - tokenURL = "", - clientId = "", - clientSecret = "", - timeoutMs = DEFAULT_TIMEOUT_MS, - fetchImpl, - } = {}) { - this.adminClientsURL = trimString(adminClientsURL); - this.tokenURL = trimString(tokenURL); - this.clientId = trimString(clientId); - this.clientSecret = trimString(clientSecret); - this.timeoutMs = Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : DEFAULT_TIMEOUT_MS; - this.fetch = resolveFetch(fetchImpl); - } - - static fromEnv() { - const adminBase = buildUrlFromEnv(process.env.KEYCLOAK_BASE_URL, process.env.KEYCLOAK_REALM, "/admin/realms/"); - const adminClientsURL = adminBase ? `${adminBase}/clients` : ""; - - const tokenBase = buildUrlFromEnv(process.env.KEYCLOAK_BASE_URL, process.env.KEYCLOAK_REALM, "/realms/"); - const tokenURL = tokenBase ? `${tokenBase}/protocol/openid-connect/token` : ""; - - return new KeycloakService({ - adminClientsURL, - tokenURL, - clientId: process.env.AUTH_CLIENT_ID, - clientSecret: process.env.AUTH_CLIENT_SECRET, - }); - } - - isConfigured() { - return ( - Boolean(this.adminClientsURL) && Boolean(this.tokenURL) && Boolean(this.clientId) && Boolean(this.clientSecret) - ); - } - - async createClient(input) { - if (!this.isConfigured()) { - throw new KeycloakError("Keycloak configuratie ontbreekt", ERROR_CODES.CONFIG); - } - - const email = trimString(typeof input === "string" ? input : input?.email); - - const token = await this.fetchToken(); - const clientId = randomUUID(); - const payload = buildKeycloakPayload(clientId, email); - - const { signal, cleanup } = createTimeoutSignal(this.timeoutMs); - let response; - try { - response = await this.fetch(this.adminClientsURL, { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${token}`, - }, - body: JSON.stringify(payload), - signal, - }); - } catch (error) { - if (error.name === "TimeoutError" || error.name === "AbortError") { - throw new KeycloakError("Timeout tijdens verzoek naar Keycloak", ERROR_CODES.GENERIC); - } - throw new KeycloakError(`Netwerkfout richting Keycloak: ${error.message}`, ERROR_CODES.GENERIC); - } finally { - cleanup(); - } - - const responseText = truncate(await response.text()); - - switch (response.status) { - case 201: { - const location = response.headers.get("location"); - const newClientId = extractClientIdFromLocation(location); - return { - apiKey: newClientId, - }; - } - case 204: - throw new KeycloakError("clientId ontbreekt of is ongeldig", ERROR_CODES.CLIENT_ID_MISSING); - case 409: - throw new KeycloakError("Keycloak client bestaat al", ERROR_CODES.CONFLICT); - case 401: - case 403: - throw new KeycloakError("Geen toegang tot Keycloak admin API", ERROR_CODES.UNAUTHORIZED); - default: { - const message = responseText || response.statusText || "Onbekende fout"; - throw new KeycloakError(`Keycloak response ${response.status}: ${message}`, ERROR_CODES.GENERIC); - } - } - } - - async fetchToken() { - if (!this.tokenURL || !this.clientId || !this.clientSecret) { - throw new KeycloakError("Keycloak configuratie ontbreekt", ERROR_CODES.CONFIG); - } - - const body = new URLSearchParams({ - grant_type: "client_credentials", - client_id: this.clientId, - client_secret: this.clientSecret, - }); - - const { signal, cleanup } = createTimeoutSignal(this.timeoutMs); - let response; - try { - response = await this.fetch(this.tokenURL, { - method: "POST", - headers: { - "Content-Type": "application/x-www-form-urlencoded", - Accept: "application/json", - }, - body, - signal, - }); - } catch (error) { - if (error.name === "TimeoutError" || error.name === "AbortError") { - throw new KeycloakError("Timeout tijdens ophalen van Keycloak token", ERROR_CODES.GENERIC); - } - throw new KeycloakError(`Netwerkfout richting Keycloak token endpoint: ${error.message}`, ERROR_CODES.GENERIC); - } finally { - cleanup(); - } - - const text = truncate(await response.text()); - if (!response.ok) { - const unauthorizedStatuses = new Set([400, 401, 403]); - if (unauthorizedStatuses.has(response.status)) { - throw new KeycloakError("autorisatie voor keycloak mislukt", ERROR_CODES.UNAUTHORIZED); - } - throw new KeycloakError( - `Keycloak token response ${response.status}: ${text || response.statusText}`, - ERROR_CODES.GENERIC, - ); - } - - let parsed; - try { - parsed = JSON.parse(text || "{}"); - } catch { - throw new KeycloakError("Keycloak token response bevat geen geldig JSON", ERROR_CODES.GENERIC); - } - - const token = trimString(parsed.access_token); - if (!token) { - throw new KeycloakError("Keycloak token ontbreekt in response", ERROR_CODES.GENERIC); - } - return token; - } -} - -module.exports = { - KeycloakService, - KeycloakError, - ERROR_CODES, - parseUntrustClientInput, - translateKeycloakError, -}; diff --git a/services/OasBundleService.js b/services/OasBundleService.js deleted file mode 100644 index 9d9051d..0000000 --- a/services/OasBundleService.js +++ /dev/null @@ -1,160 +0,0 @@ -const fs = require("node:fs/promises"); -const os = require("node:os"); -const path = require("node:path"); -const { URL } = require("node:url"); -const { execFile } = require("node:child_process"); -const { promisify } = require("node:util"); -const jsYaml = require("js-yaml"); -const Service = require("./Service"); -const { resolveOasInput } = require("./OasInputService"); -const { sanitizeFileName } = require("../utils/fileName"); -const logger = require("../logger"); - -const DEFAULT_FILENAME = "openapi"; -const REDOCLY_BIN = require.resolve("@redocly/cli/bin/cli"); -const execFileAsync = promisify(execFile); - -const guessPreferredExtension = (contents) => { - if (typeof contents !== "string") { - return ".json"; - } - const trimmed = contents.trimStart(); - if (trimmed.startsWith("{") || trimmed.startsWith("[")) { - return ".json"; - } - return ".yaml"; -}; - -const deriveDocumentName = (doc, source) => { - if (doc && typeof doc === "object" && !Array.isArray(doc)) { - const infoTitle = typeof doc.info?.title === "string" ? doc.info.title.trim() : ""; - if (infoTitle) { - const sanitized = sanitizeFileName(infoTitle, { fallback: DEFAULT_FILENAME }); - if (sanitized) { - return sanitized; - } - } - } - if (typeof source === "string" && source !== "request-body") { - try { - const parsed = new URL(source); - const basePath = parsed.pathname || ""; - if (basePath) { - const basename = path.posix.basename(basePath); - const withoutExt = basename.replace(/\.[^.]+$/, ""); - const sanitized = sanitizeFileName(withoutExt, { fallback: DEFAULT_FILENAME }); - if (sanitized) { - return sanitized; - } - } - } catch { - // ignore invalid URL - } - } - return DEFAULT_FILENAME; -}; - -const runRedoclyBundle = async (inputPath, outputPath, ext) => { - const args = [ - REDOCLY_BIN, - "bundle", - inputPath, - "--output", - outputPath, - "--ext", - ext, - "--dereferenced", - ]; - return execFileAsync(process.execPath, args, { maxBuffer: 20 * 1024 * 1024 }); -}; - -const bundle = async (input) => { - const resolved = await resolveOasInput(input); - const contents = typeof resolved.contents === "string" ? resolved.contents : ""; - if (!contents.trim()) { - throw Service.rejectResponse( - { - message: "Body ontbreekt of ongeldig: gebruik oasUrl of oasBody.", - }, - 400, - ); - } - - let tmpDir; - const inputExt = guessPreferredExtension(contents); - const inputPath = () => path.join(tmpDir, `input${inputExt}`); - const outputPath = (ext) => path.join(tmpDir, `bundle.${ext}`); - - let bundledText; - let document; - let outputExt = "json"; - try { - tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "oas-bundle-")); - await fs.writeFile(inputPath(), contents, "utf8"); - try { - await runRedoclyBundle(inputPath(), outputPath("json"), "json"); - bundledText = await fs.readFile(outputPath("json"), "utf8"); - document = JSON.parse(bundledText); - } catch (jsonError) { - const errText = `${jsonError?.stderr || ""}${jsonError?.stdout || ""}${jsonError?.message || ""}`; - const hasCircular = errText.toLowerCase().includes("circular reference"); - if (!hasCircular) { - throw jsonError; - } - logger.warn("[OasBundleService] JSON bundle failed due to circular refs, retrying with YAML", { - message: jsonError?.message, - }); - outputExt = "yaml"; - await runRedoclyBundle(inputPath(), outputPath("yaml"), "yaml"); - bundledText = await fs.readFile(outputPath("yaml"), "utf8"); - document = jsYaml.load(bundledText); - } - } catch (error) { - logger.error("[OasBundleService] bundle failed via redocly CLI", { - message: error?.message, - stack: error?.stack, - }); - const status = typeof error?.status === "number" && error.status >= 400 ? error.status : 400; - throw Service.rejectResponse( - { - message: "Het bundelen van de OpenAPI specificatie is mislukt.", - detail: error?.message, - }, - status, - ); - } finally { - if (tmpDir) { - try { - await fs.rm(tmpDir, { recursive: true, force: true }); - } catch { - // ignore cleanup errors - } - } - } - - if (!document || typeof document !== "object" || Array.isArray(document)) { - throw Service.rejectResponse( - { - message: "Onverwachte structuur na bundelen.", - }, - 500, - ); - } - - const docName = deriveDocumentName(document, resolved.source); - const buffer = Buffer.from(bundledText, "utf8"); - const filename = `${docName}.${outputExt}`; - const contentType = outputExt === "json" ? "application/json" : "application/yaml"; - - return { - headers: { - "Content-Type": contentType, - "Content-Disposition": `attachment; filename="${filename}"`, - }, - rawBody: buffer, - }; -}; - -module.exports = { - bundle, -}; diff --git a/services/OasConversionService.js b/services/OasConversionService.js deleted file mode 100644 index d851085..0000000 --- a/services/OasConversionService.js +++ /dev/null @@ -1,187 +0,0 @@ -const { Converter } = require("@apiture/openapi-down-convert"); -const { upgrade: scalarUpgrade } = require("@scalar/openapi-upgrader"); -const jsYaml = require("js-yaml"); -const Service = require("./Service"); -const { resolveOasInput } = require("./OasInputService"); -const logger = require("../logger"); - -const DEFAULT_TARGET_VERSION = "3.1.0"; - -const EMPTY_BODY_ERROR = "Body ontbreekt of ongeldig: gebruik oasUrl of oasBody"; -const VERSION_MISSING_ERROR = "OpenAPI document bevat geen geldig openapi versieveld"; -const UNSUPPORTED_VERSION_ERROR = "Alleen OpenAPI 3.0 en 3.1 worden ondersteund"; -const UNSUPPORTED_TARGET_VERSION_ERROR = "targetVersion wordt niet ondersteund. Gebruik 3.0 of 3.1."; - -const parseSpecification = (contents) => { - const trimmed = contents.trim(); - if (trimmed.length === 0) { - throw Service.rejectResponse({ message: EMPTY_BODY_ERROR }, 400); - } - try { - const spec = JSON.parse(trimmed); - if (!spec || typeof spec !== "object" || Array.isArray(spec)) { - throw new Error("Ongeldig OpenAPI document"); - } - return { spec, format: "json" }; - } catch (_jsonError) { - try { - const spec = jsYaml.load(trimmed); - if (!spec || typeof spec !== "object" || Array.isArray(spec)) { - throw new Error("Ongeldig OpenAPI document"); - } - return { spec, format: "yaml" }; - } catch (yamlError) { - throw new Error(`Kan OpenAPI specificatie niet parseren: ${yamlError.message}`); - } - } -}; - -const resolveVersionDescriptor = (value) => { - const raw = - typeof value === "number" && Number.isFinite(value) - ? value.toString() - : typeof value === "string" - ? value.trim() - : ""; - if (!raw) { - return null; - } - if (raw === "3") { - return { major: "3.0", canonical: "3.0.3" }; - } - if (raw.startsWith("3.0")) { - return { major: "3.0", canonical: "3.0.3" }; - } - if (raw.startsWith("3.1")) { - return { major: "3.1", canonical: "3.1.0" }; - } - return null; -}; - -const normalizeTargetVersion = (value) => { - if (typeof value !== "string" || value.trim().length === 0) { - return DEFAULT_TARGET_VERSION; - } - const descriptor = resolveVersionDescriptor(value); - if (!descriptor) { - throw Service.rejectResponse( - { - message: UNSUPPORTED_TARGET_VERSION_ERROR, - }, - 400, - ); - } - return descriptor.canonical; -}; - -const ensureObjectSpec = (value, errorMessage) => { - if (!value || typeof value !== "object" || Array.isArray(value)) { - throw new Error(errorMessage); - } - return value; -}; - -const convertSpec = async (spec, targetVersion, options = {}) => { - const sourceDescriptor = resolveVersionDescriptor(spec.openapi); - const rawVersion = spec.openapi == null ? "" : String(spec.openapi).trim(); - if (rawVersion.length === 0 || !sourceDescriptor) { - throw Service.rejectResponse({ message: VERSION_MISSING_ERROR }, 400); - } - - const targetDescriptor = resolveVersionDescriptor(targetVersion); - if (!targetDescriptor) { - throw Service.rejectResponse({ message: UNSUPPORTED_TARGET_VERSION_ERROR }, 400); - } - - if (sourceDescriptor.major === targetDescriptor.major) { - if (options.preserveSourceVersion && sourceDescriptor.major === "3.1") { - spec.openapi = rawVersion; - return { spec, resolvedVersion: rawVersion }; - } - spec.openapi = targetDescriptor.canonical; - return { spec, resolvedVersion: targetDescriptor.canonical }; - } - - if (sourceDescriptor.major === "3.0" && targetDescriptor.major === "3.1") { - const upgraded = ensureObjectSpec( - scalarUpgrade(spec, "3.1"), - "Scalar OpenAPI upgrader retourneerde een ongeldig document.", - ); - upgraded.openapi = targetDescriptor.canonical; - return { spec: upgraded, resolvedVersion: targetDescriptor.canonical }; - } - - if (sourceDescriptor.major === "3.1" && targetDescriptor.major === "3.0") { - const downConverter = new Converter(spec); - const downgraded = ensureObjectSpec( - downConverter.convert(), - "OpenAPI down converter retourneerde een ongeldig document.", - ); - downgraded.openapi = targetDescriptor.canonical; - return { spec: downgraded, resolvedVersion: targetDescriptor.canonical }; - } - - throw Service.rejectResponse({ message: UNSUPPORTED_VERSION_ERROR }, 400); -}; - -const serializeSpecification = (spec, format, targetVersion) => { - const filenameBase = `openapi-${targetVersion.replace(/\./g, "-")}`; - if (format === "json") { - const json = JSON.stringify(spec, null, 2); - return { - buffer: Buffer.from(json, "utf8"), - contentType: "application/json", - filename: `${filenameBase}.json`, - }; - } - const yaml = jsYaml.dump(spec, { lineWidth: -1 }); - return { - buffer: Buffer.from(yaml, "utf8"), - contentType: "application/yaml", - filename: `${filenameBase}.yaml`, - }; -}; - -const convert = async (input) => { - const requestedTargetVersion = typeof input?.targetVersion === "string" ? input.targetVersion : undefined; - const targetVersion = normalizeTargetVersion(requestedTargetVersion); - const hasExplicitTargetVersion = - typeof requestedTargetVersion === "string" && requestedTargetVersion.trim().length > 0; - const { contents } = await resolveOasInput(input); - let parsed; - try { - parsed = parseSpecification(contents); - } catch (error) { - if (Service.isErrorResponse(error)) throw error; - logger.error(`[OasConversionService] parseSpecification failed: ${error?.message}`); - throw Service.rejectResponse({ message: error.message }, 500); - } - - const { spec, format } = parsed; - let convertedSpec, resolvedVersion; - try { - ({ spec: convertedSpec, resolvedVersion } = await convertSpec(spec, targetVersion, { - preserveSourceVersion: !hasExplicitTargetVersion, - })); - } catch (error) { - if (Service.isErrorResponse(error)) throw error; - logger.error(`[OasConversionService] convertSpec failed: ${error?.message}`); - throw Service.rejectResponse( - { message: error.message || "Er is een fout opgetreden tijdens het converteren." }, - 500, - ); - } - - const { buffer, contentType, filename } = serializeSpecification(convertedSpec, format, resolvedVersion); - return { - headers: { - "Content-Type": contentType, - "Content-Disposition": `attachment; filename="${filename}"`, - }, - rawBody: buffer, - }; -}; - -module.exports = { - convert, -}; diff --git a/services/OasGeneratorService.js b/services/OasGeneratorService.js deleted file mode 100644 index 87a8485..0000000 --- a/services/OasGeneratorService.js +++ /dev/null @@ -1,359 +0,0 @@ -const { kebabCase, upperCamelCase } = require("case-anything"); -const Service = require("./Service"); -const { resolveOasInput } = require("./OasInputService"); -const { sanitizeFileName } = require("../utils/fileName"); -const logger = require("../logger"); - -const EMPTY_BODY_ERROR = "Body ontbreekt of heeft een ongeldig formaat."; -const INVALID_JSON_ERROR = "Het aangeleverde JSON-document kon niet worden gelezen."; -const MISSING_VALUE_ERROR = (field) => `Eigenschap '${field}' ontbreekt of is ongeldig.`; -const NO_RESOURCES_ERROR = "Geef minimaal één resource op in het 'resources' veld."; - -const toUppercase = (value) => { - if (typeof value !== "string" || value.length === 0) { - return ""; - } - return value.charAt(0).toUpperCase() + value.slice(1); -}; - -const requireString = (value, fieldName) => { - if (typeof value !== "string" || value.trim().length === 0) { - throw Service.rejectResponse( - { - message: MISSING_VALUE_ERROR(fieldName), - detail: `${fieldName} moet een niet-lege string zijn.`, - }, - 400, - ); - } - return value.trim(); -}; - -const requireObject = (value, fieldName) => { - if (!value || typeof value !== "object" || Array.isArray(value)) { - throw Service.rejectResponse( - { - message: MISSING_VALUE_ERROR(fieldName), - detail: `${fieldName} moet een object zijn.`, - }, - 400, - ); - } - return value; -}; - -const normalizeContact = (contact) => { - const source = requireObject(contact, "contact"); - return { - name: requireString(source.name, "contact.name"), - email: requireString(source.email, "contact.email"), - url: requireString(source.url, "contact.url"), - }; -}; - -const normalizeResources = (resources) => { - if (!Array.isArray(resources) || resources.length === 0) { - throw Service.rejectResponse( - { - message: NO_RESOURCES_ERROR, - detail: NO_RESOURCES_ERROR, - }, - 400, - ); - } - return resources.map((resource, index) => { - const source = requireObject(resource, `resources[${index}]`); - return { - name: requireString(source.name, `resources[${index}].name`), - plural: requireString(source.plural, `resources[${index}].plural`), - readonly: Boolean(source.readonly), - }; - }); -}; - -const parseGeneratorConfig = (contents) => { - if (typeof contents !== "string" || contents.trim().length === 0) { - throw Service.rejectResponse( - { - message: EMPTY_BODY_ERROR, - }, - 400, - ); - } - try { - const parsed = JSON.parse(contents); - const normalized = requireObject(parsed, "root"); - return { - title: requireString(normalized.title, "title"), - description: requireString(normalized.description, "description"), - contact: normalizeContact(normalized.contact), - resources: normalizeResources(normalized.resources), - }; - } catch (error) { - if (Service.isErrorResponse(error)) { - throw error; - } - throw Service.rejectResponse( - { - message: INVALID_JSON_ERROR, - detail: error?.message || INVALID_JSON_ERROR, - }, - 400, - ); - } -}; - -const createEndpointSingle = (resource) => { - const baseName = upperCamelCase(resource.name); - const schemaRef = `#/components/schemas/${baseName}`; - const pluralLabel = toUppercase(resource.plural); - const singularLabel = toUppercase(resource.name); - const endpoint = { - parameters: [ - { - $ref: "#/components/parameters/id", - }, - ], - get: { - operationId: `retrieve${baseName}`, - description: `${singularLabel} ophalen`, - summary: `${singularLabel} ophalen`, - tags: [pluralLabel], - responses: { - 200: { - headers: { - "API-Version": { - $ref: "https://static.developer.overheid.nl/adr/components.yaml#/headers/API-Version", - }, - }, - description: "OK", - content: { - "application/json": { - schema: { - $ref: schemaRef, - }, - }, - }, - }, - 404: { - $ref: "https://static.developer.overheid.nl/adr/components.yaml#/responses/404", - }, - }, - }, - }; - if (!resource.readonly) { - endpoint.put = { - operationId: `edit${baseName}`, - description: `${singularLabel} wijzigen`, - summary: `${singularLabel} wijzigen`, - tags: [pluralLabel], - responses: { - 200: { - headers: { - "API-Version": { - $ref: "https://static.developer.overheid.nl/adr/components.yaml#/headers/API-Version", - }, - }, - description: "OK", - content: { - "application/json": { - schema: { - $ref: schemaRef, - }, - }, - }, - }, - 400: { - $ref: "https://static.developer.overheid.nl/adr/components.yaml#/responses/400", - }, - }, - }; - endpoint.delete = { - operationId: `remove${baseName}`, - description: `${singularLabel} verwijderen`, - summary: `${singularLabel} verwijderen`, - tags: [pluralLabel], - responses: { - 204: { - $ref: "https://static.developer.overheid.nl/adr/components.yaml#/responses/204", - }, - 404: { - $ref: "https://static.developer.overheid.nl/adr/components.yaml#/responses/404", - }, - }, - }; - } - return endpoint; -}; - -const createEndpointList = (resource) => { - const pluralName = upperCamelCase(resource.plural); - const schemaRef = `#/components/schemas/${upperCamelCase(resource.name)}`; - const pluralLabel = toUppercase(resource.plural); - const endpoint = { - get: { - operationId: `list${pluralName}`, - description: `Alle ${resource.plural} ophalen`, - summary: `Alle ${resource.plural} ophalen`, - tags: [pluralLabel], - responses: { - 200: { - headers: { - "API-Version": { - $ref: "https://static.developer.overheid.nl/adr/components.yaml#/headers/API-Version", - }, - Link: { - $ref: "https://static.developer.overheid.nl/adr/components.yaml#/headers/Link", - }, - }, - description: "OK", - content: { - "application/json": { - schema: { - $ref: schemaRef, - }, - }, - }, - }, - }, - }, - }; - if (!resource.readonly) { - endpoint.post = { - operationId: `create${pluralName}`, - description: `Nieuwe ${resource.name} aanmaken`, - summary: `Nieuwe ${resource.name} aanmaken`, - tags: [pluralLabel], - responses: { - 201: { - headers: { - "API-Version": { - $ref: "https://static.developer.overheid.nl/adr/components.yaml#/headers/API-Version", - }, - }, - description: "Created", - content: { - "application/json": { - schema: { - $ref: schemaRef, - }, - }, - }, - }, - 400: { - $ref: "https://static.developer.overheid.nl/adr/components.yaml#/responses/400", - }, - }, - }; - } - return endpoint; -}; - -const createPaths = (resources) => - resources.reduce((paths, resource) => { - const pluralPath = kebabCase(resource.plural); - paths[`/${pluralPath}`] = createEndpointList(resource); - paths[`/${pluralPath}/{id}`] = createEndpointSingle(resource); - return paths; - }, {}); - -const createSchemas = (resources) => - resources.reduce((schemas, resource) => { - const schemaName = upperCamelCase(resource.name); - schemas[schemaName] = { - type: "object", - properties: { - id: { - type: "string", - format: "uuid", - }, - }, - }; - return schemas; - }, {}); - -const buildOpenApiDocument = (config) => ({ - openapi: "3.0.2", - info: { - title: config.title, - description: config.description, - version: "1.0.0", - contact: { - name: config.contact.name, - email: config.contact.email, - url: config.contact.url, - }, - }, - servers: [ - { - url: "@TODO: Add server URL", - }, - ], - tags: config.resources.map((resource) => { - const tag = toUppercase(resource.plural); - return { - name: tag, - description: `Alle API operaties die bij ${resource.plural} horen.`, - }; - }), - paths: createPaths(config.resources), - components: { - schemas: createSchemas(config.resources), - parameters: { - id: { - name: "id", - in: "path", - description: "id", - required: true, - schema: { - type: "string", - }, - }, - }, - }, -}); - -const deriveFilename = (title) => { - const sanitized = sanitizeFileName(title, { fallback: "openapi-boilerplate", lowercase: true }); - return (sanitized && `${sanitized}.json`) || "openapi-boilerplate.json"; -}; - -const generate = async (input) => { - const { contents } = await resolveOasInput(input); - let config; - try { - config = parseGeneratorConfig(contents); - } catch (error) { - logger.error(`[OasGeneratorService] parseGeneratorConfig failed: ${error?.detail || error?.message || "unknown"}`); - throw error; - } - - try { - const document = buildOpenApiDocument(config); - const filename = deriveFilename(config.title); - const buffer = Buffer.from(JSON.stringify(document, null, 2), "utf8"); - return { - headers: { - "Content-Type": "application/json", - "Content-Disposition": `attachment; filename="${filename}"`, - }, - rawBody: buffer, - }; - } catch (error) { - logger.error( - `[OasGeneratorService] buildOpenApiDocument failed: ${error?.message || "unknown"}${ - error?.stack ? ` stack=${error.stack}` : "" - }`, - ); - throw Service.rejectResponse( - { - message: "Er is een fout opgetreden tijdens het genereren van de OpenAPI specificatie.", - }, - 500, - ); - } -}; - -module.exports = { - generate, -}; diff --git a/services/OasInputService.js b/services/OasInputService.js deleted file mode 100644 index 7034289..0000000 --- a/services/OasInputService.js +++ /dev/null @@ -1,50 +0,0 @@ -const Service = require("./Service"); -const { fetchSpecification } = require("./RemoteSpecificationService"); - -const resolveOasInput = async (input) => { - if (!input || typeof input !== "object") { - throw Service.rejectResponse( - { - message: "Body ontbreekt of heeft een ongeldig formaat.", - }, - 400, - ); - } - const { oasBody, oasUrl } = input; - if (typeof oasBody === "string" && oasBody.trim().length > 0) { - return { - source: "request-body", - contents: oasBody, - }; - } - if (typeof oasUrl === "string" && oasUrl.trim().length > 0) { - let parsedUrl; - try { - parsedUrl = new URL(oasUrl); - } catch { - throw Service.rejectResponse( - { - message: "De waarde van oasUrl is geen geldige URL.", - }, - 400, - ); - } - const contents = await fetchSpecification(parsedUrl.toString(), { - errorMessage: "Het ophalen van de OpenAPI specificatie is mislukt.", - }); - return { - source: parsedUrl.toString(), - contents, - }; - } - throw Service.rejectResponse( - { - message: "Geef een oasBody of oasUrl mee.", - }, - 400, - ); -}; - -module.exports = { - resolveOasInput, -}; diff --git a/services/OasValidatorService.js b/services/OasValidatorService.js deleted file mode 100644 index a09e26f..0000000 --- a/services/OasValidatorService.js +++ /dev/null @@ -1,216 +0,0 @@ -const { randomUUID } = require("node:crypto"); -const { Spectral, Document } = require("@stoplight/spectral-core"); -const Parsers = require("@stoplight/spectral-parsers"); -const Service = require("./Service"); -const { fetchSpecification } = require("./RemoteSpecificationService"); -const logger = require("../logger"); - -const RULESET_LOADERS = { - "2.0": () => import("@developer-overheid-nl/adr-rulesets/rulesets/adr-20"), - "2.1": () => import("@developer-overheid-nl/adr-rulesets/rulesets/adr-21"), -}; -const DEFAULT_RULESET_VERSION = "2.1"; - -const SEVERITY_LABELS = ["error", "warning", "info", "hint"]; - -const MEASURED_RULE_GROUPS = { - openapi3: "openapi3", - "nlgov:openapi3": "openapi3", - "openapi-root-exists": "openapi-root-exists", - "nlgov:openapi-root-exists": "openapi-root-exists", - "missing-version-header": "version-header", - "nlgov:missing-version-header": "version-header", - "missing-header": "version-header", - "nlgov:missing-header": "version-header", - "include-major-version-in-uri": "include-major-version-in-uri", - "nlgov:include-major-version-in-uri": "include-major-version-in-uri", - "paths-no-trailing-slash": "paths-no-trailing-slash", - "nlgov:paths-no-trailing-slash": "paths-no-trailing-slash", - "info-contact-fields-exist": "info-contact-fields-exist", - "nlgov:info-contact-fields-exist": "info-contact-fields-exist", - "http-methods": "http-methods", - "nlgov:http-methods": "http-methods", - semver: "semver", - "nlgov:semver": "semver", -}; - -const MEASURED_GROUP_KEYS = Array.from(new Set(Object.values(MEASURED_RULE_GROUPS))); - -const spectralInstancePromises = new Map(); - -const loadSpectral = (rulesetVersion) => { - if (!spectralInstancePromises.has(rulesetVersion)) { - const promise = (async () => { - try { - const loader = RULESET_LOADERS[rulesetVersion]; - const module = await loader(); - const spectral = new Spectral(); - spectral.setRuleset(module.default); - return spectral; - } catch (error) { - logger.error(`[OasValidatorService] Unable to load ruleset (${rulesetVersion}): ${error.message}`); - spectralInstancePromises.delete(rulesetVersion); - throw Service.rejectResponse( - { - message: "Kan het regels-bestand niet laden voor validatie.", - detail: error.message, - }, - 500, - ); - } - })(); - spectralInstancePromises.set(rulesetVersion, promise); - } - return spectralInstancePromises.get(rulesetVersion); -}; - -const resolveSpecificationInput = async (input) => { - if (!input || typeof input !== "object") { - throw Service.rejectResponse( - { - message: "Body ontbreekt of heeft een ongeldig formaat.", - }, - 400, - ); - } - const { oasBody, oasUrl } = input; - if (typeof oasBody === "string" && oasBody.trim().length > 0) { - return { - source: "request-body", - contents: oasBody, - }; - } - if (typeof oasUrl === "string" && oasUrl.trim().length > 0) { - let parsedUrl; - try { - parsedUrl = new URL(oasUrl); - } catch (error) { - logger.error("[OasValidatorService] invalid oasUrl", { message: error.message }); - throw Service.rejectResponse( - { - message: "De waarde van oasUrl is geen geldige URL.", - }, - 400, - ); - } - const contents = await fetchSpecification(parsedUrl.toString(), { - errorMessage: "Het ophalen van de OpenAPI specificatie is mislukt.", - }); - return { - source: parsedUrl.toString(), - contents, - }; - } - throw Service.rejectResponse( - { - message: "Geef een oasBody of oasUrl mee.", - }, - 400, - ); -}; - -const buildInfo = (lintMessageId, diagnostic) => { - const pathValue = - Array.isArray(diagnostic.path) && diagnostic.path.length > 0 ? diagnostic.path.map(String).join(".") : "body"; - return [ - { - id: randomUUID(), - lintMessageId, - message: diagnostic.message, - path: pathValue, - }, - ]; -}; - -const mapDiagnosticsToMessages = (diagnostics, timestamp) => - diagnostics.map((diagnostic) => { - const lintMessageId = randomUUID(); - const severityIndex = typeof diagnostic.severity === "number" && diagnostic.severity >= 0 ? diagnostic.severity : 2; - const severity = SEVERITY_LABELS[severityIndex] || "info"; - return { - id: lintMessageId, - code: diagnostic.code ? String(diagnostic.code) : "spectral", - createdAt: timestamp, - severity, - infos: buildInfo(lintMessageId, diagnostic), - }; - }); - -const computeAdrScore = (messages) => { - const failedGroups = new Set(); - messages.forEach((message) => { - if (String(message.severity).toLowerCase() !== "error") { - return; - } - const group = MEASURED_RULE_GROUPS[message.code]; - if (group) { - failedGroups.add(group); - } - }); - - if (MEASURED_GROUP_KEYS.length === 0) { - return { score: 100, failedGroups: [] }; - } - - const score = Math.round((1 - failedGroups.size / MEASURED_GROUP_KEYS.length) * 100); - return { - score: Math.max(0, Math.min(100, score)), - failedGroups: Array.from(failedGroups).sort(), - }; -}; - -const buildLintResult = (diagnostics, rulesetVersion) => { - const timestamp = new Date().toISOString(); - const messages = mapDiagnosticsToMessages(diagnostics, timestamp); - const errorCount = messages.filter((message) => String(message.severity).toLowerCase() === "error").length; - const { score } = computeAdrScore(messages); - return { - id: randomUUID(), - apiId: "", - createdAt: timestamp, - failures: errorCount, - messages, - score, - successes: score === 100, - rulesetVersion, - }; -}; - -const normalizeRulesetVersion = (value) => { - if (typeof value === "number" && Number.isFinite(value)) { - value = value.toString(); - } - if (typeof value !== "string") { - return DEFAULT_RULESET_VERSION; - } - const trimmed = value.trim(); - if (trimmed === "2") { - return "2.0"; - } - if (Object.hasOwn(RULESET_LOADERS, trimmed)) { - return trimmed; - } - return DEFAULT_RULESET_VERSION; -}; - -const resolveValidationSettings = (input) => ({ - rulesetVersion: normalizeRulesetVersion(input?.targetVersion), -}); - -const validate = async (input) => { - const { contents, source } = await resolveSpecificationInput(input); - const { rulesetVersion } = resolveValidationSettings(input); - logger.info( - `[OasValidatorService] validate using ADR ruleset ${rulesetVersion} (targetVersion=${input?.targetVersion || "default"}, source=${source})`, - ); - const spectral = await loadSpectral(rulesetVersion); - const document = new Document(contents, Parsers.Yaml, source); - const parseDiagnostics = Array.isArray(document.diagnostics) ? document.diagnostics : []; - const lintDiagnostics = await spectral.run(document, { ignoreUnknownFormat: false }); - const diagnostics = [...parseDiagnostics, ...lintDiagnostics]; - return buildLintResult(diagnostics, rulesetVersion); -}; - -module.exports = { - validate, -}; diff --git a/services/PostmanConversionService.js b/services/PostmanConversionService.js deleted file mode 100644 index 15842a3..0000000 --- a/services/PostmanConversionService.js +++ /dev/null @@ -1,90 +0,0 @@ -const Service = require("./Service"); -const { resolveOasInput } = require("./OasInputService"); -const openapiToPostman = require("openapi-to-postmanv2"); -const { sanitizeFileName } = require("../utils/fileName"); - -const EMPTY_BODY_ERROR = "Body ontbreekt of ongeldig: gebruik oasUrl of oasBody"; -const DEFAULT_COLLECTION_NAME = "postman-collection"; - -const convertToPostman = (data) => - new Promise((resolve, reject) => { - openapiToPostman.convert({ type: "string", data }, {}, (error, result) => { - if (error) { - reject(error); - return; - } - if (!result || result.result !== true) { - const reason = - result && typeof result.reason === "string" ? result.reason : "Conversie naar Postman is mislukt."; - reject(new Error(reason)); - return; - } - resolve(result); - }); - }); - -const convert = async (input) => { - let resolved; - try { - resolved = await resolveOasInput(input); - } catch (error) { - if (Service.isErrorResponse(error)) { - throw error; - } - throw Service.rejectResponse( - { - message: error.message || "Er is een fout opgetreden tijdens het lezen van de input.", - }, - 500, - ); - } - - const trimmed = typeof resolved.contents === "string" ? resolved.contents.trim() : ""; - if (!trimmed) { - throw Service.rejectResponse({ message: EMPTY_BODY_ERROR }, 400); - } - - let conversionResult; - try { - conversionResult = await convertToPostman(trimmed); - } catch (error) { - throw Service.rejectResponse( - { - message: error.message || "Conversie naar Postman is mislukt.", - }, - 500, - ); - } - - const collectionOutput = Array.isArray(conversionResult.output) - ? conversionResult.output.find((item) => item.type === "collection") - : null; - if (!collectionOutput || !collectionOutput.data) { - throw Service.rejectResponse( - { - message: "Conversie naar Postman heeft geen collectie opgeleverd.", - }, - 500, - ); - } - - const collection = collectionOutput.data; - const collectionName = collection?.info?.name || DEFAULT_COLLECTION_NAME; - const filenameBase = sanitizeFileName(collectionName, { - fallback: DEFAULT_COLLECTION_NAME, - lowercase: true, - }); - const json = JSON.stringify(collection, null, 2); - - return { - headers: { - "Content-Type": "application/json", - "Content-Disposition": `attachment; filename="${filenameBase}.json"`, - }, - rawBody: Buffer.from(json, "utf8"), - }; -}; - -module.exports = { - convert, -}; diff --git a/services/RemoteSpecificationService.js b/services/RemoteSpecificationService.js deleted file mode 100644 index d974988..0000000 --- a/services/RemoteSpecificationService.js +++ /dev/null @@ -1,95 +0,0 @@ -const { fetch } = require("@stoplight/spectral-runtime"); -const Service = require("./Service"); -const logger = require("../logger"); - -const DEFAULT_ERROR_MESSAGE = "Het ophalen van de specificatie is mislukt."; -const DEFAULT_TIMEOUT_MS = 45000; - -const resolveTimeoutMs = () => { - const envValue = Number(process.env.OAS_FETCH_TIMEOUT_MS); - if (Number.isFinite(envValue) && envValue > 0) { - return envValue; - } - return DEFAULT_TIMEOUT_MS; -}; - -const buildFetchOptions = (url) => { - const controller = new AbortController(); - const timeout = resolveTimeoutMs(); - const timeoutId = setTimeout(() => controller.abort(), timeout); - const options = { - signal: controller.signal, - }; - return { options, cleanup: () => clearTimeout(timeoutId), timeout }; -}; - -const normalizeErrorDetail = (error) => { - const parts = []; - if (error?.message) { - parts.push(error.message); - } - if (error?.code) { - parts.push(`code=${error.code}`); - } - if (error?.type) { - parts.push(`type=${error.type}`); - } - return parts.join(" ").trim() || "Onbekende netwerkfout"; -}; - -const doFetch = async (url, { origin }) => { - const { options, cleanup, timeout } = buildFetchOptions(url); - try { - const headers = {}; - if (origin) { - headers.Origin = origin; - } - options.headers = headers; - const response = await fetch(url, options); - if (!response.ok) { - const preview = await response.text().catch(() => ""); - const trimmed = preview ? preview.slice(0, 200) : ""; - throw new Error(`Server gaf status ${response.status}${trimmed ? `: ${trimmed}` : ""}`); - } - return await response.text(); - } catch (error) { - error.timeout = timeout; - throw error; - } finally { - cleanup(); - } -}; - -const fetchSpecification = async (url, { errorMessage = DEFAULT_ERROR_MESSAGE } = {}) => { - const origin = "https://developer.overheid.nl"; - const attempts = origin ? [{ origin }, { origin: undefined }] : [{ origin: undefined }]; - let lastError; - for (const attempt of attempts) { - try { - return await doFetch(url, attempt); - } catch (error) { - lastError = error; - const detail = normalizeErrorDetail(error); - logger.error( - `[RemoteSpecificationService] fetch failed for ${url} (${attempt.origin ? "with" : "without"} Origin): ${detail}${ - error?.stack ? ` stack=${error.stack}` : "" - }`, - ); - // continue to next attempt - } - } - - const detail = normalizeErrorDetail(lastError); - throw Service.rejectResponse( - { - message: errorMessage, - detail, - timeout: lastError?.timeout, - }, - 400, - ); -}; - -module.exports = { - fetchSpecification, -}; diff --git a/services/Service.js b/services/Service.js deleted file mode 100644 index f516d8b..0000000 --- a/services/Service.js +++ /dev/null @@ -1,454 +0,0 @@ -const fs = require("node:fs"); -const path = require("node:path"); -const config = require("../config"); -const logger = require("../logger"); - -class Service { - static rejectResponse(error, code = 500) { - return { error, code }; - } - - static successResponse(payload, code = 200) { - return { payload, code }; - } - - static isErrorResponse(result) { - return Boolean(result && Object.hasOwn(result, "error") && Object.hasOwn(result, "code")); - } - - static normalizeSuccessResponse(result) { - if (result === undefined) { - return undefined; - } - if (result && Object.hasOwn(result, "payload")) { - return result; - } - return Service.successResponse(result); - } - - static extractRequestBody(params) { - if (!params || typeof params !== "object") { - return params; - } - if (params.body !== undefined) { - return params.body; - } - if (params.OASInput !== undefined) { - return params.OASInput; - } - if (params.oASInput !== undefined) { - return params.oASInput; - } - const entries = Object.entries(params); - if (entries.length === 1) { - return entries[0][1]; - } - return params; - } - - static throwHttpError(status, message, detail = undefined) { - throw Service.rejectResponse( - { - message, - detail: detail || message, - }, - status, - ); - } - - static getMockModule(serviceName) { - if (!config.USE_MOCKS) { - return null; - } - if (!Object.hasOwn(Service.mockModules, serviceName)) { - const mockPath = path.join(config.MOCK_DIR, `${serviceName}.js`); - if (!fs.existsSync(mockPath)) { - Service.mockModules[serviceName] = null; - return null; - } - try { - // eslint-disable-next-line global-require, import/no-dynamic-require - Service.mockModules[serviceName] = require(mockPath); - } catch (error) { - logger.error(`Unable to load mock implementation for ${serviceName}: ${error.message}`); - Service.mockModules[serviceName] = null; - } - } - return Service.mockModules[serviceName]; - } - - /** - * Returns undefined when no mock is available. Otherwise resolves to an object describing - * how the caller should respond (resolve/reject) with the normalized payload. - */ - static async applyMock(serviceName, operationId, params) { - if (!config.USE_MOCKS) { - return undefined; - } - let autoMockEvaluated = false; - let autoMock; - const resolveAutoMock = () => { - if (!autoMockEvaluated) { - autoMock = Service.generateAutoMock(operationId); - autoMockEvaluated = true; - } - return autoMock; - }; - const mockModule = Service.getMockModule(serviceName); - if (!mockModule) { - const generated = resolveAutoMock(); - if (generated !== undefined) { - logger.info(`[Mock] Using autogenerated payload for ${serviceName}.${operationId}`); - return { action: "resolve", value: generated }; - } - return undefined; - } - const handler = mockModule[operationId]; - if (typeof handler !== "function") { - const generated = resolveAutoMock(); - if (generated !== undefined) { - logger.info(`[Mock] Using autogenerated payload for ${serviceName}.${operationId}`); - return { action: "resolve", value: generated }; - } - return undefined; - } - try { - const result = await handler(params); - if (result === undefined) { - const generated = resolveAutoMock(); - if (generated !== undefined) { - logger.info(`[Mock] Using autogenerated payload for ${serviceName}.${operationId}`); - return { action: "resolve", value: generated }; - } - return undefined; - } - if (Service.isErrorResponse(result)) { - logger.info(`[Mock] Returning custom error response for ${serviceName}.${operationId}`); - return { action: "reject", value: result }; - } - logger.info(`[Mock] Returning custom mock payload for ${serviceName}.${operationId}`); - return { action: "resolve", value: Service.normalizeSuccessResponse(result) }; - } catch (error) { - if (Service.isErrorResponse(error)) { - logger.warn(`[Mock] Mock handler threw mock error for ${serviceName}.${operationId}`); - return { action: "reject", value: error }; - } - throw error; - } - } - - static getApiDoc() { - if (Service.apiDoc !== undefined) { - return Service.apiDoc; - } - try { - const specContents = fs.readFileSync(config.OPENAPI_JSON, "utf8"); - Service.apiDoc = JSON.parse(specContents); - } catch (error) { - logger.error(`Unable to load OpenAPI spec for auto mocks: ${error.message}`); - Service.apiDoc = null; - } - return Service.apiDoc; - } - - static buildOperationIndex() { - if (Service.operationIndex !== undefined) { - return Service.operationIndex; - } - const apiDoc = Service.getApiDoc(); - const index = {}; - if (apiDoc?.paths) { - Object.keys(apiDoc.paths).forEach((pathKey) => { - const pathItem = apiDoc.paths[pathKey]; - Object.keys(pathItem).forEach((methodKey) => { - const operation = pathItem[methodKey]; - if (!operation || typeof operation !== "object" || !operation.operationId) { - return; - } - const { operationId } = operation; - if (!operationId) { - return; - } - const entry = { - path: pathKey, - method: methodKey, - operation, - }; - index[operationId] = entry; - const sanitizedId = Service.sanitizeOperationId(operationId); - if (sanitizedId && sanitizedId !== operationId) { - index[sanitizedId] = entry; - } - const lowerId = operationId.toLowerCase(); - if (lowerId !== operationId && lowerId !== sanitizedId && !Object.hasOwn(index, lowerId)) { - index[lowerId] = entry; - } - }); - }); - } - Service.operationIndex = index; - return index; - } - - static resolveRef(ref) { - if (typeof ref !== "string" || !ref.startsWith("#/")) { - return undefined; - } - const apiDoc = Service.getApiDoc(); - if (!apiDoc) { - return undefined; - } - const parts = ref.replace("#/", "").split("/"); - let current = apiDoc; - for (let i = 0; i < parts.length; i += 1) { - const part = parts[i]; - if (!Object.hasOwn(current, part)) { - return undefined; - } - current = current[part]; - } - return current; - } - - static sanitizeOperationId(operationId) { - if (!operationId || typeof operationId !== "string") { - return null; - } - let result = operationId.trim(); - if (result.length === 0) { - return null; - } - result = result.replace(/[_-]+/g, " "); - result = result.replace(/[^a-zA-Z0-9_$]+/g, " "); - result = result - .split(" ") - .filter((segment) => segment.length > 0) - .map((segment, index) => { - if (index === 0) { - return segment; - } - return segment.charAt(0).toUpperCase() + segment.slice(1); - }) - .join(""); - result = result.replace(/^[^a-zA-Z_$]+/, ""); - if (result.length === 0) { - return null; - } - return result.charAt(0).toLowerCase() + result.slice(1); - } - - static pickPreferredMedia(content) { - if (!content || typeof content !== "object") { - return null; - } - if (content["application/json"]) { - return content["application/json"]; - } - if (content["application/problem+json"]) { - return content["application/problem+json"]; - } - const firstKey = Object.keys(content)[0]; - return firstKey ? content[firstKey] : null; - } - - static clone(value) { - if (value === undefined) { - return value; - } - try { - return JSON.parse(JSON.stringify(value)); - } catch (_error) { - return value; - } - } - - static primitiveExample(schema) { - if (!schema || typeof schema !== "object") { - return null; - } - if (schema.example !== undefined) { - return Service.clone(schema.example); - } - if (schema.default !== undefined) { - return Service.clone(schema.default); - } - if (schema.enum && schema.enum.length > 0) { - return Service.clone(schema.enum[0]); - } - switch (schema.type) { - case "string": - if (schema.format === "date-time") return new Date().toISOString(); - if (schema.format === "date") return new Date().toISOString().split("T")[0]; - if (schema.format === "uuid") return "00000000-0000-4000-8000-000000000000"; - return "string"; - case "integer": - case "number": - return 0; - case "boolean": - return true; - default: - return null; - } - } - - static generateExampleFromSchema(schema, stack = new Set()) { - if (!schema || typeof schema !== "object") { - return undefined; - } - if (schema.$ref) { - if (stack.has(schema.$ref)) { - return undefined; - } - stack.add(schema.$ref); - const resolved = Service.resolveRef(schema.$ref); - if (!resolved) { - return undefined; - } - const result = Service.generateExampleFromSchema(resolved, stack); - stack.delete(schema.$ref); - return result; - } - - const primitive = Service.primitiveExample(schema); - if (primitive !== null) { - return primitive; - } - - if (schema.type === "array") { - const itemExample = Service.generateExampleFromSchema(schema.items, stack); - return itemExample !== undefined ? [itemExample] : []; - } - - if (schema.type === "object" || schema.properties) { - const obj = {}; - const properties = schema.properties || {}; - const propertyNames = Object.keys(properties); - propertyNames.forEach((name) => { - const exampleValue = Service.generateExampleFromSchema(properties[name], stack); - if (exampleValue !== undefined) { - obj[name] = exampleValue; - } - }); - if (schema.additionalProperties && typeof schema.additionalProperties === "object") { - const additionalExample = Service.generateExampleFromSchema(schema.additionalProperties, stack); - if (additionalExample !== undefined) { - obj.additionalProperty = additionalExample; - } - } - return obj; - } - - if (schema.allOf && Array.isArray(schema.allOf)) { - return schema.allOf.reduce((acc, partialSchema) => { - const partialExample = Service.generateExampleFromSchema(partialSchema, stack); - if (partialExample === undefined) { - return acc; - } - if (partialExample && typeof partialExample === "object" && !Array.isArray(partialExample)) { - return { ...acc, ...partialExample }; - } - return partialExample; - }, {}); - } - - if (schema.oneOf && Array.isArray(schema.oneOf) && schema.oneOf.length > 0) { - return Service.generateExampleFromSchema(schema.oneOf[0], stack); - } - - if (schema.anyOf && Array.isArray(schema.anyOf) && schema.anyOf.length > 0) { - return Service.generateExampleFromSchema(schema.anyOf[0], stack); - } - - return undefined; - } - - static extractExampleFromResponse(response) { - if (!response) { - return undefined; - } - let resolvedResponse = response; - if (typeof resolvedResponse === "string") { - const dereferenced = Service.resolveRef(resolvedResponse); - if (dereferenced) { - resolvedResponse = dereferenced; - } - } - if (resolvedResponse && typeof resolvedResponse === "object" && resolvedResponse.$ref) { - const dereferenced = Service.resolveRef(resolvedResponse.$ref); - if (dereferenced) { - resolvedResponse = dereferenced; - } - } - if (!resolvedResponse || typeof resolvedResponse !== "object") { - return undefined; - } - const media = Service.pickPreferredMedia(resolvedResponse.content); - if (!media) { - return undefined; - } - if (media.example !== undefined) { - return Service.clone(media.example); - } - if (media.examples && typeof media.examples === "object") { - const firstExample = Object.values(media.examples)[0]; - if (firstExample && typeof firstExample === "object") { - if (firstExample.value !== undefined) { - return Service.clone(firstExample.value); - } - } - } - if (media.schema) { - return Service.generateExampleFromSchema(media.schema); - } - return undefined; - } - - static pickResponse(operation) { - if (!operation || !operation.responses) { - return null; - } - const preferredStatuses = ["200", "201", "202", "204"]; - for (let i = 0; i < preferredStatuses.length; i += 1) { - const status = preferredStatuses[i]; - if (operation.responses[status]) { - return { status, response: operation.responses[status] }; - } - } - const statusCodes = Object.keys(operation.responses); - if (statusCodes.length === 0) { - return null; - } - return { status: statusCodes[0], response: operation.responses[statusCodes[0]] }; - } - - static generateAutoMock(operationId) { - const operationIndex = Service.buildOperationIndex(); - const operationEntry = operationIndex[operationId]; - if (!operationEntry) { - return undefined; - } - const { operation } = operationEntry; - const responseInfo = Service.pickResponse(operation); - if (!responseInfo) { - return undefined; - } - const examplePayload = Service.extractExampleFromResponse(responseInfo.response); - const parsedStatus = Number.parseInt(responseInfo.status, 10); - const statusCode = Number.isNaN(parsedStatus) ? 200 : parsedStatus; - if (examplePayload === undefined) { - return Service.successResponse( - { - message: `Auto-generated mock for ${operationId}`, - }, - statusCode, - ); - } - return Service.successResponse(examplePayload, statusCode); - } -} - -Service.mockModules = {}; -Service.apiDoc = undefined; -Service.operationIndex = undefined; - -module.exports = Service; diff --git a/services/ToolsService.js b/services/ToolsService.js deleted file mode 100644 index 40d4786..0000000 --- a/services/ToolsService.js +++ /dev/null @@ -1,295 +0,0 @@ -/* eslint-disable no-unused-vars */ -const Service = require("./Service"); -const OasConversionService = require("./OasConversionService"); -const OasBundleService = require("./OasBundleService"); -const OasValidatorService = require("./OasValidatorService"); -const OasGeneratorService = require("./OasGeneratorService"); -const PostmanConversionService = require("./PostmanConversionService"); -const ArazzoVisualizationService = require("./ArazzoVisualizationService"); -const { KeycloakService, parseUntrustClientInput, translateKeycloakError } = require("./KeycloakService"); -const logger = require("../logger"); - -const keycloakService = KeycloakService.fromEnv(); - -const CONTENT_TYPE_MARKDOWN = "text/markdown; charset=utf-8"; -const CONTENT_TYPE_TEXT = "text/plain; charset=utf-8"; - -const normalizeError = (error) => { - if (Service.isErrorResponse(error)) { - const status = typeof error.code === "number" ? error.code : 400; - const message = error.error?.message || "Er is een fout opgetreden."; - const detail = error.error?.detail || message; - return { status, message, detail }; - } - const status = typeof error?.status === "number" && error.status > 0 ? error.status : 400; - const message = error?.message || "Er is een fout opgetreden."; - const detail = error?.detail || message; - return { status, message, detail }; -}; - -const logServiceError = (operation, error) => { - const { detail } = normalizeError(error); - const stack = error?.stack ? ` stack=${error.stack}` : ""; - logger.error(`[ToolsService] ${operation} failed: ${detail}${stack}`); -}; - -const handleArazzoVisualization = async ({ operationId, params, pick, contentType }) => { - try { - const mockResult = await Service.applyMock("ToolsService", operationId, params); - if (mockResult !== undefined) { - if (mockResult.action === "reject") { - throw mockResult.value; - } - return mockResult.value; - } - const requestPayload = Service.extractRequestBody(params); - const visualization = await ArazzoVisualizationService.visualize(requestPayload); - const body = pick(visualization) || ""; - return { - code: 200, - headers: { - "Content-Type": contentType, - }, - payload: body, - }; - } catch (e) { - logServiceError(operationId, e); - const { status, message, detail } = normalizeError(e); - throw Service.rejectResponse({ message, detail }, status); - } -}; - -/** - * Arazzo Markdown (POST) - * Genereert alleen de Markdown-uitvoer van een Arazzo specificatie. - * - * arazzoInput ArazzoInput (optional) - * no response value expected for this operation - */ -const arazzoMarkdown = async (params) => - handleArazzoVisualization({ - operationId: "arazzoMarkdown", - params, - pick: (visualization) => visualization.markdown, - contentType: CONTENT_TYPE_MARKDOWN, - }); - -/** - * Arazzo Mermaid (POST) - * Genereert de Mermaid flowchart van een Arazzo specificatie. - * - * arazzoInput ArazzoInput (optional) - * no response value expected for this operation - */ -const arazzoMermaid = async (params) => - handleArazzoVisualization({ - operationId: "arazzoMermaid", - params, - pick: (visualization) => visualization.mermaid, - contentType: CONTENT_TYPE_TEXT, - }); - -/** - * Converteer OpenAPI 3.0/3.1 - * Converteert standaard naar 3.1. Geef targetVersion (3.0 of 3.1) mee om een doelversie te forceren. Body: { oasUrl } of { oasBody } (stringified JSON of YAML). - * - * oASInput OASInput (optional) - * no response value expected for this operation - */ -// const convertOAS = async ({ oASInput }) => { -const convertOAS = async (params) => { - try { - const mockResult = await Service.applyMock("ToolsService", "convertOAS", params); - if (mockResult !== undefined) { - if (mockResult.action === "reject") { - throw mockResult.value; - } - return mockResult.value; - } - const requestPayload = Service.extractRequestBody(params); - const result = await OasConversionService.convert(requestPayload); - return { - code: 200, - headers: result.headers, - payload: result.rawBody, - }; - } catch (e) { - logServiceError("convertOAS", e); - const { status, message, detail } = normalizeError(e); - throw Service.rejectResponse({ message, detail }, status); - } -}; - -/** - * Maak Postman-collectie (POST) - * Converteert OpenAPI naar Postman Collection JSON. Body: { oasUrl } of { oasBody } (stringified JSON of YAML). - * - * oASInput OASInput (optional) - * no response value expected for this operation - */ -// const createPostmanCollection = async ({ oASInput }) => { -const createPostmanCollection = async (params) => { - try { - const mockResult = await Service.applyMock("ToolsService", "createPostmanCollection", params); - if (mockResult !== undefined) { - if (mockResult.action === "reject") { - throw mockResult.value; - } - return mockResult.value; - } - const requestPayload = Service.extractRequestBody(params); - const result = await PostmanConversionService.convert(requestPayload); - return { - code: 200, - headers: result.headers, - payload: result.rawBody, - }; - } catch (e) { - logServiceError("createPostmanCollection", e); - const { status, message, detail } = normalizeError(e); - throw Service.rejectResponse({ message, detail }, status); - } -}; - -/** - * Bundle OpenAPI - * Maakt één gebundeld OpenAPI document met opgeloste verwijzingen. Body: { oasUrl } of { oasBody }. - * - * oASInput OASInput (optional) - * no response value expected for this operation - */ -const bundleOAS = async (params) => { - try { - const mockResult = await Service.applyMock("ToolsService", "bundleOAS", params); - if (mockResult !== undefined) { - if (mockResult.action === "reject") { - throw mockResult.value; - } - return mockResult.value; - } - const requestPayload = Service.extractRequestBody(params); - const result = await OasBundleService.bundle(requestPayload); - return { - code: 200, - headers: result.headers, - payload: result.rawBody, - }; - } catch (e) { - logServiceError("bundleOAS", e); - const { status, message, detail } = normalizeError(e); - throw Service.rejectResponse({ message, detail }, status); - } -}; - -/** - * Generate OpenAPI - * Genereert een boilerplate OpenAPI document op basis van JSON-input. Body: { oasUrl } of { oasBody } (stringified JSON). - * - * oASInput OASInput (optional) - * no response value expected for this operation - */ -// const generateOAS = async ({ oASInput }) => { -const generateOAS = async (params) => { - try { - const mockResult = await Service.applyMock("ToolsService", "generateOAS", params); - if (mockResult !== undefined) { - if (mockResult.action === "reject") { - throw mockResult.value; - } - return mockResult.value; - } - const requestPayload = Service.extractRequestBody(params); - const result = await OasGeneratorService.generate(requestPayload); - return { - code: 200, - headers: result.headers, - payload: result.rawBody, - }; - } catch (e) { - logServiceError("generateOAS", e); - const { status, message, detail } = normalizeError(e); - throw Service.rejectResponse({ message, detail }, status); - } -}; - -/** - * Maak client (POST) - * Maak een client aan via de admin API. Body bevat Email. - * - * untrustClientInput UntrustClientInput (optional) - * returns ModelsKeycloakClientResult - */ -// const untrustClient = async ({ untrustClientInput }) => { -const untrustClient = async (params) => { - try { - const mockResult = await Service.applyMock("ToolsService", "untrustClient", params); - if (mockResult !== undefined) { - if (mockResult.action === "reject") { - throw mockResult.value; - } - return mockResult.value; - } - const { email } = parseUntrustClientInput(params); - if (!keycloakService.isConfigured()) { - Service.throwHttpError(500, "Keycloak service niet geconfigureerd"); - } - const result = await keycloakService.createClient({ email }); - return Service.successResponse(result); - } catch (e) { - logServiceError("untrustClient", e); - if (Service.isErrorResponse(e)) { - throw e; - } - const mapped = translateKeycloakError(e); - if (mapped) { - Service.throwHttpError(mapped.status, mapped.message); - } - const status = typeof e.status === "number" && e.status > 0 ? e.status : 400; - const message = e?.message ? e.message : "Er is een fout opgetreden."; - throw Service.rejectResponse( - { - message, - detail: e.detail || message, - }, - status, - ); - } -}; - -/** - * Validate OpenAPI (POST) - * Valideert een OpenAPI specificatie met de DON ADR ruleset. Body: { oasUrl } of { oasBody } (stringified JSON of YAML). - * - * oASInput OASInput (optional) - * returns ModelsLintResult - */ -// const validatorOpenAPIPost = async ({ oASInput }) => { -const validatorOpenAPIPost = async (params) => { - try { - const mockResult = await Service.applyMock("ToolsService", "validatorOpenAPIPost", params); - if (mockResult !== undefined) { - if (mockResult.action === "reject") { - throw mockResult.value; - } - return mockResult.value; - } - const requestPayload = Service.extractRequestBody(params); - const result = await OasValidatorService.validate(requestPayload); - return Service.successResponse(result); - } catch (e) { - logServiceError("validatorOpenAPIPost", e); - const { status, message, detail } = normalizeError(e); - throw Service.rejectResponse({ message, detail }, status); - } -}; - -module.exports = { - arazzoMarkdown, - arazzoMermaid, - convertOAS, - createPostmanCollection, - bundleOAS, - generateOAS, - untrustClient, - validatorOpenAPIPost, -}; diff --git a/services/ZipService.js b/services/ZipService.js deleted file mode 100644 index 3d4a013..0000000 --- a/services/ZipService.js +++ /dev/null @@ -1,38 +0,0 @@ -const JSZip = require("jszip"); - -const isBufferLike = (value) => Buffer.isBuffer(value) || value instanceof Uint8Array; - -const createZipFromEntries = async (entries, options = {}) => { - if (!Array.isArray(entries)) { - throw new TypeError("entries must be an array"); - } - - const zip = new JSZip(); - entries.forEach((entry) => { - if (!entry || typeof entry !== "object") { - throw new TypeError("Each entry must be an object with path and contents"); - } - const { path, contents, fileOptions } = entry; - if (typeof path !== "string" || path.trim().length === 0) { - throw new TypeError("Each entry must provide a non-empty string path"); - } - if (!isBufferLike(contents) && typeof contents !== "string") { - throw new TypeError(`Unsupported contents type for ${path}. Use string or Buffer.`); - } - zip.file(path, contents, fileOptions); - }); - - const compression = options.compression ?? "DEFLATE"; - const compressionOptions = options.compressionOptions ?? { level: 9 }; - - return zip.generateAsync({ - type: "nodebuffer", - compression, - compressionOptions, - streamFiles: true, - }); -}; - -module.exports = { - createZipFromEntries, -}; diff --git a/services/index.js b/services/index.js deleted file mode 100644 index 61a7144..0000000 --- a/services/index.js +++ /dev/null @@ -1,5 +0,0 @@ -const ToolsService = require("./ToolsService"); - -module.exports = { - ToolsService, -}; diff --git a/test/OasConversionService.test.js b/test/OasConversionService.test.js deleted file mode 100644 index fa8f1b5..0000000 --- a/test/OasConversionService.test.js +++ /dev/null @@ -1,155 +0,0 @@ -const assert = require("node:assert/strict"); -const test = require("node:test"); -const jsYaml = require("js-yaml"); -const OasConversionService = require("../services/OasConversionService"); - -const toJson = (buffer) => JSON.parse(buffer.toString("utf8")); -const toYaml = (buffer) => jsYaml.load(buffer.toString("utf8")); - -test("convert 3.0 -> 3.1 (JSON) upgrades key OpenAPI features", async () => { - const sourceSpec = { - openapi: "3.0.3", - info: { - title: "Test API", - version: "1.0.0", - }, - paths: {}, - "x-webhooks": { - onEvent: { - post: { - responses: { - 200: { - description: "OK", - }, - }, - }, - }, - }, - components: { - schemas: { - Pet: { - type: "object", - properties: { - nickname: { - type: "string", - nullable: true, - }, - }, - }, - }, - }, - }; - - const result = await OasConversionService.convert({ - oasBody: JSON.stringify(sourceSpec), - targetVersion: "3.1", - }); - - const converted = toJson(result.rawBody); - - assert.equal(result.headers["Content-Type"], "application/json"); - assert.equal(result.headers["Content-Disposition"], 'attachment; filename="openapi-3-1-0.json"'); - assert.equal(converted.openapi, "3.1.0"); - assert.ok(Object.hasOwn(converted, "webhooks")); - assert.ok(!Object.hasOwn(converted, "x-webhooks")); - assert.deepEqual(converted.components.schemas.Pet.properties.nickname.type, ["string", "null"]); -}); - -test("convert 3.1 -> 3.0 (JSON) downgrades key OpenAPI features", async () => { - const sourceSpec = { - openapi: "3.1.0", - info: { - title: "Test API", - version: "1.0.0", - }, - paths: {}, - webhooks: { - onEvent: { - post: { - responses: { - 200: { - description: "OK", - }, - }, - }, - }, - }, - components: { - schemas: { - Pet: { - type: "object", - properties: { - nickname: { - type: ["string", "null"], - }, - }, - }, - }, - }, - }; - - const result = await OasConversionService.convert({ - oasBody: JSON.stringify(sourceSpec), - targetVersion: "3.0", - }); - - const converted = toJson(result.rawBody); - - assert.equal(result.headers["Content-Type"], "application/json"); - assert.equal(result.headers["Content-Disposition"], 'attachment; filename="openapi-3-0-3.json"'); - assert.equal(converted.openapi, "3.0.3"); - assert.ok(!Object.hasOwn(converted, "webhooks")); - assert.equal(converted.components.schemas.Pet.properties.nickname.type, "string"); - assert.equal(converted.components.schemas.Pet.properties.nickname.nullable, true); -}); - -test("convert preserves YAML format in response", async () => { - const sourceSpecYaml = ` -openapi: 3.0.3 -info: - title: Test API - version: 1.0.0 -paths: {} -components: - schemas: - Item: - type: object - properties: - maybeText: - type: string - nullable: true -`; - - const result = await OasConversionService.convert({ - oasBody: sourceSpecYaml, - targetVersion: "3.1", - }); - - const converted = toYaml(result.rawBody); - - assert.equal(result.headers["Content-Type"], "application/yaml"); - assert.equal(result.headers["Content-Disposition"], 'attachment; filename="openapi-3-1-0.yaml"'); - assert.equal(converted.openapi, "3.1.0"); - assert.deepEqual(converted.components.schemas.Item.properties.maybeText.type, ["string", "null"]); -}); - -test("convert without targetVersion keeps existing 3.1 patch version", async () => { - const sourceSpec = { - openapi: "3.1.2", - info: { - title: "Test API", - version: "1.0.0", - }, - paths: {}, - }; - - const result = await OasConversionService.convert({ - oasBody: JSON.stringify(sourceSpec), - }); - - const converted = toJson(result.rawBody); - - assert.equal(result.headers["Content-Type"], "application/json"); - assert.equal(result.headers["Content-Disposition"], 'attachment; filename="openapi-3-1-2.json"'); - assert.equal(converted.openapi, "3.1.2"); -}); diff --git a/test/app.test.ts b/test/app.test.ts new file mode 100644 index 0000000..2cd7a13 --- /dev/null +++ b/test/app.test.ts @@ -0,0 +1,62 @@ +import { afterAll, beforeAll, describe, expect, it } from "vitest"; +import type { NestFastifyApplication } from "@nestjs/platform-fastify"; +import { createApp } from "../app/index.ts"; + +let app: NestFastifyApplication; + +beforeAll(async () => { + app = await createApp(); + await app.init(); +}); + +afterAll(async () => { + await app.close(); +}); + +const inject = async (options: { method: string; url: string; payload?: unknown }) => + app.getHttpAdapter().getInstance().inject(options); + +describe("app", () => { + it("serves the OpenAPI spec", async () => { + const response = await inject({ method: "GET", url: "/openapi.json" }); + expect(response.statusCode).toBe(200); + const body = response.json() as { info: { title: string } }; + expect(body.info.title).toBe("Tools API v1"); + }); + + it("returns API-Version header", async () => { + const response = await inject({ method: "GET", url: "/openapi.json" }); + expect(response.headers["api-version"]).toBe("1.0.0"); + }); + + it("returns problem+json on unknown route", async () => { + const response = await inject({ method: "GET", url: "/no-such-route" }); + expect(response.statusCode).toBe(404); + expect(response.headers["content-type"]).toContain("application/problem+json"); + expect(response.json()).toMatchObject({ status: 404, title: "Cannot GET /no-such-route" }); + }); + + it("returns problem+json on validation failure", async () => { + const response = await inject({ + method: "POST", + url: "/v1/oas/validate", + payload: {}, + }); + expect(response.statusCode).toBe(400); + expect(response.headers["content-type"]).toContain("application/problem+json"); + }); + + it("converts OpenAPI through the logic package", async () => { + const response = await inject({ + method: "POST", + url: "/v1/oas/convert", + payload: { + oasBody: JSON.stringify({ openapi: "3.0.3", info: { title: "T", version: "1.0.0" }, paths: {} }), + targetVersion: "3.1", + }, + }); + expect(response.statusCode).toBe(200); + expect(response.headers["content-type"]).toContain("application/json"); + expect(JSON.parse(response.body)).toMatchObject({ openapi: "3.1.0" }); + }); +}); diff --git a/test/convert-oas.test.ts b/test/convert-oas.test.ts new file mode 100644 index 0000000..3d36eef --- /dev/null +++ b/test/convert-oas.test.ts @@ -0,0 +1,54 @@ +import { describe, expect, it } from "vitest"; +import jsYaml from "js-yaml"; +import { convertOAS } from "@developer-overheid-nl/don-tools-logic"; + +const toJson = (buffer: Buffer) => JSON.parse(buffer.toString("utf8")); +const toYaml = (buffer: Buffer) => jsYaml.load(buffer.toString("utf8")) as Record; + +describe("convertOAS", () => { + it("upgrades 3.0 -> 3.1 (JSON)", async () => { + const sourceSpec = { + openapi: "3.0.3", + info: { title: "Test API", version: "1.0.0" }, + paths: {}, + "x-webhooks": { onEvent: { post: { responses: { 200: { description: "OK" } } } } }, + components: { + schemas: { Pet: { type: "object", properties: { nickname: { type: "string", nullable: true } } } }, + }, + }; + + const result = await convertOAS({ oasBody: JSON.stringify(sourceSpec), targetVersion: "3.1" }); + const converted = toJson(result.rawBody); + + expect(result.headers["Content-Type"]).toBe("application/json"); + expect(result.headers["Content-Disposition"]).toBe('attachment; filename="openapi-3-1-0.json"'); + expect(converted.openapi).toBe("3.1.0"); + expect(Object.hasOwn(converted, "webhooks")).toBe(true); + expect(Object.hasOwn(converted, "x-webhooks")).toBe(false); + expect(converted.components.schemas.Pet.properties.nickname.type).toEqual(["string", "null"]); + }); + + it("preserves YAML format", async () => { + const yaml = ` +openapi: 3.0.3 +info: + title: Test API + version: 1.0.0 +paths: {} +components: + schemas: + Item: + type: object + properties: + maybeText: + type: string + nullable: true +`; + const result = await convertOAS({ oasBody: yaml, targetVersion: "3.1" }); + const converted = toYaml(result.rawBody); + + expect(result.headers["Content-Type"]).toBe("application/yaml"); + expect(result.headers["Content-Disposition"]).toBe('attachment; filename="openapi-3-1-0.yaml"'); + expect((converted as { openapi: string }).openapi).toBe("3.1.0"); + }); +}); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..f025710 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "module": "commonjs", + "declaration": true, + "removeComments": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "target": "ES2023", + "sourceMap": true, + "outDir": "./dist", + "incremental": true, + "skipLibCheck": true, + "strictNullChecks": true, + "noImplicitAny": false, + "strictBindCallApply": false, + "noFallthroughCasesInSwitch": false + }, + "include": [ + "api/**/*.ts", + "controllers/**/*.ts", + "decorators/**/*.ts", + "models/**/*.ts", + "app/**/*.ts", + "implementation/**/*.ts" + ], + "exclude": ["node_modules", "dist", "src", "test"] +} diff --git a/utils/fileName.js b/utils/fileName.js deleted file mode 100644 index d167eda..0000000 --- a/utils/fileName.js +++ /dev/null @@ -1,58 +0,0 @@ -const DEFAULT_MAX_LENGTH = 128; - -const internalSanitize = (value, { lowercase, maxLength }) => { - if (typeof value !== "string") { - return ""; - } - - let working = value.trim(); - if (working.length === 0) { - return ""; - } - - try { - working = working.normalize("NFKD").replace(/\p{M}+/gu, ""); - } catch { - // ignore environments without String.prototype.normalize - } - - working = working - .replace(/["']/g, "") - .replace(/\p{Cc}+/gu, " ") - .replace(/[<>:"/\\|?*]+/g, "-") - .replace(/[^0-9A-Za-z._\s-]+/g, "-") - .replace(/\s+/g, "-") - .replace(/-+/g, "-") - .replace(/^[-_.]+|[-_.]+$/g, "") - .trim(); - - if (lowercase) { - working = working.toLowerCase(); - } - - if (maxLength > 0 && working.length > maxLength) { - working = working.slice(0, maxLength); - } - - return working; -}; - -const sanitizeFileName = (value, options = {}) => { - const { fallback = "", lowercase = false, maxLength = DEFAULT_MAX_LENGTH } = options; - const params = { lowercase, maxLength }; - const sanitized = internalSanitize(value, params); - if (sanitized) { - return sanitized; - } - if (typeof fallback === "string" && fallback.length > 0) { - const fallbackSanitized = internalSanitize(fallback, params); - if (fallbackSanitized) { - return fallbackSanitized; - } - } - return ""; -}; - -module.exports = { - sanitizeFileName, -}; diff --git a/utils/openapiRouter.js b/utils/openapiRouter.js deleted file mode 100644 index 8813d6c..0000000 --- a/utils/openapiRouter.js +++ /dev/null @@ -1,71 +0,0 @@ -const logger = require("../logger"); -const controllers = require("../controllers"); -const Services = require("../services"); - -function handleError(err, _request, response, next) { - logger.error(err); - const code = err.code || 400; - response.status(code); - response.error = err; - next( - JSON.stringify({ - code, - error: err, - }), - ); -} - -/** - * The purpose of this route is to collect the request variables as defined in the - * OpenAPI document and pass them to the handling controller as another Express - * middleware. All parameters are collected in the request.swagger.values key-value object - * - * The assumption is that security handlers have already verified and allowed access - * to this path. If the business-logic of a particular path is dependent on authentication - * parameters (e.g. scope checking) - it is recommended to define the authentication header - * as one of the parameters expected in the OpenAPI/Swagger document. - * - * Requests made to paths that are not in the OpenAPI scope - * are passed on to the next middleware handler. - * @returns {Function} - */ -function openApiRouter() { - return async (request, response, next) => { - try { - /** - * This middleware runs after a previous process have applied an openapi object - * to the request. - * If none was applied This is because the path requested is not in the schema. - * If there's no openapi object, we have nothing to do, and pass on to next middleware. - */ - if (request.openapi === undefined || request.openapi.schema === undefined) { - next(); - return; - } - // request.swagger.paramValues = {}; - // request.swagger.params.forEach((param) => { - // request.swagger.paramValues[param.name] = getValueFromRequest(request, param); - // }); - const controllerName = request.openapi.schema["x-openapi-router-controller"]; - const serviceName = request.openapi.schema["x-openapi-router-service"]; - if (!controllers[controllerName] || controllers[controllerName] === undefined) { - handleError( - `request sent to controller '${controllerName}' which has not been defined`, - request, - response, - next, - ); - } else { - const apiController = new controllers[controllerName](Services[serviceName]); - const controllerOperation = request.openapi.schema.operationId; - await apiController[controllerOperation](request, response, next); - } - } catch (error) { - console.error(error); - const err = { code: 500, error: error.message }; - handleError(err, request, response, next); - } - }; -} - -module.exports = openApiRouter; diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..0deaed0 --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + include: ["test/**/*.test.ts"], + environment: "node", + testTimeout: 30000, + }, +});