diff --git a/.dockerignore b/.dockerignore index f9e552cc..630c7988 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,4 +1,4 @@ * !src !package*.json -!tsconfig.server.json +!tsconfig*.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..f27f863b --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @supabase/api @supabase/frontend diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 5bfeb20e..6ebae6b8 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,20 +1,10 @@ version: 2 updates: - - # github actions - - package-ecosystem: "github-actions" directory: "/" schedule: - interval: "weekly" - open-pull-requests-limit: 5 - labels: ["github-actions", "dependencies", "pr/automerge"] - - # npm - + interval: "daily" - package-ecosystem: "npm" directory: "/" schedule: - interval: "weekly" - open-pull-requests-limit: 15 - labels: ["npm", "dependencies", "pr/automerge"] + interval: "daily" diff --git a/.github/workflows/automerge.yml b/.github/workflows/automerge.yml new file mode 100644 index 00000000..1604962b --- /dev/null +++ b/.github/workflows/automerge.yml @@ -0,0 +1,31 @@ +name: Dependabot auto-merge +on: pull_request + +permissions: + contents: write + pull-requests: write + +jobs: + dependabot: + runs-on: ubuntu-latest + if: ${{ github.actor == 'dependabot[bot]' }} + steps: + - name: Dependabot metadata + id: metadata + uses: dependabot/fetch-metadata@v2 + with: + github-token: "${{ secrets.GITHUB_TOKEN }}" + + - name: Approve a PR + if: ${{ steps.metadata.outputs.update-type != 'version-update:semver-major' && !startswith(steps.metadata.outputs.new_version, '0.') }} + run: gh pr review --approve "$PR_URL" + env: + PR_URL: ${{ github.event.pull_request.html_url }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Enable auto-merge for Dependabot PRs + if: ${{ steps.metadata.outputs.update-type != 'version-update:semver-major' && !startswith(steps.metadata.outputs.new_version, '0.') }} + run: gh pr merge --auto --squash "$PR_URL" + env: + PR_URL: ${{ github.event.pull_request.html_url }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b8b14c2e..ac0d7539 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,27 +7,92 @@ on: - master workflow_dispatch: +permissions: + contents: read + +# Cancel old builds on new commit for same workflow + branch/PR +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: test: name: Test - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: "14" + node-version-file: '.nvmrc' - run: | npm clean-install + npm run check npm run test + - uses: coverallsapp/github-action@v2 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + path-to-lcov: coverage/lcov.info + prettier-check: name: Prettier check - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + + - name: Setup node + uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + + # Installing all dependencies takes up to three minutes, hacking around to only installing prettier+deps + - name: Download dependencies + run: | + rm package.json + rm package-lock.json + npm i prettier@3 prettier-plugin-sql@0.17.0 + - name: Run prettier + run: |- + npx prettier -c '{src,test}/**/*.ts' + + docker: + name: Build with docker + runs-on: ubuntu-22.04 + permissions: + contents: read + packages: write steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + name: Checkout Repo - - uses: actionsx/prettier@v2 + - uses: docker/setup-buildx-action@v3 + name: Set up Docker Buildx + + - uses: docker/build-push-action@v5 with: - args: --check "{src,test}/**/*.ts" + push: false + tags: pg-meta:test + load: true + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Check Health status + run: | + docker run -d --name pg-meta-test pg-meta:test + state=$(docker inspect -f '{{ .State.Health.Status}}' pg-meta-test) + if [ $state != "starting" ]; then + exit 1 + fi + sleep 10 + state=$(docker inspect -f '{{ .State.Health.Status}}' pg-meta-test) + docker stop pg-meta-test + if [ $state == "healthy" ]; then + exit 0 + else + exit 1 + fi + + + diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 8a9874a7..d3645502 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -6,16 +6,25 @@ on: - master workflow_dispatch: +permissions: + contents: write + pages: write + +# Cancel old builds on new commit for same workflow + branch/PR +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: docs: name: Publish docs - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: "14" + node-version-file: '.nvmrc' - run: | npm clean-install @@ -28,7 +37,7 @@ jobs: spec-file: openapi.json - name: Publish - uses: peaceiris/actions-gh-pages@v3 + uses: peaceiris/actions-gh-pages@v4 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: docs diff --git a/.github/workflows/mirror.yml b/.github/workflows/mirror.yml new file mode 100644 index 00000000..5c56a23b --- /dev/null +++ b/.github/workflows/mirror.yml @@ -0,0 +1,39 @@ +name: Mirror Image + +on: + workflow_dispatch: + inputs: + version: + description: 'Image tag' + required: true + type: string + +permissions: + contents: read + +jobs: + mirror: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - name: configure aws credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.PROD_AWS_ROLE }} + aws-region: us-east-1 + - uses: docker/login-action@v3 + with: + registry: public.ecr.aws + - uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - uses: akhilerm/tag-push-action@v2.2.0 + with: + src: docker.io/supabase/postgres-meta:${{ inputs.version }} + dst: | + public.ecr.aws/supabase/postgres-meta:${{ inputs.version }} + ghcr.io/supabase/postgres-meta:${{ inputs.version }} diff --git a/.github/workflows/publish-deps.yml b/.github/workflows/publish-deps.yml new file mode 100644 index 00000000..7e50ecf5 --- /dev/null +++ b/.github/workflows/publish-deps.yml @@ -0,0 +1,33 @@ +name: Publish Dependencies + +on: + workflow_dispatch: + +permissions: + contents: read + packages: write + id-token: write + +jobs: + publish: + # Must match glibc verison in node:20 + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + with: + repository: 'pyramation/libpg-query-node' + ref: 'v15' + + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + + - run: npm i + - run: npm run binary:build + + - uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.PROD_AWS_ROLE }} + aws-region: us-east-1 + + - run: npx node-pre-gyp publish diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 26b2a21a..686752cd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,84 +6,89 @@ on: - master workflow_dispatch: +permissions: + contents: read + jobs: semantic-release: name: Release - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 outputs: new-release-published: ${{ steps.semantic-release.outputs.new_release_published }} new-release-version: ${{ steps.semantic-release.outputs.new_release_version }} + permissions: + contents: write steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: "16" + node-version-file: '.nvmrc' - run: | npm clean-install npm run build - id: semantic-release - uses: cycjimmy/semantic-release-action@v2 + uses: cycjimmy/semantic-release-action@v4 with: - semantic_version: 18 + semantic_version: 21 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - upload: - name: Upload assets to GitHub Releases - needs: - - semantic-release - if: needs.semantic-release.outputs.new-release-published == 'true' - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v3 - - - uses: actions/setup-node@v3 - with: - node-version: "14" - - - name: Prepare release - run: | - npm clean-install - npm run pkg - mv bin/postgres-meta-linux postgres-meta - tar -czvf postgres-meta-${{ needs.semantic-release.outputs.new-release-version }}-x86_64-linux-gnu.tar.gz postgres-meta - mv bin/postgres-meta-macos postgres-meta - tar -czvf postgres-meta-${{ needs.semantic-release.outputs.new-release-version }}-x86_64-apple-darwin.tar.gz postgres-meta - mv bin/postgres-meta-win.exe postgres-meta.exe - tar -czvf postgres-meta-${{ needs.semantic-release.outputs.new-release-version }}-x86_64-pc-windows.tar.gz postgres-meta.exe - - - uses: softprops/action-gh-release@v1 - with: - tag_name: v${{ needs.semantic-release.outputs.new-release-version }} - files: postgres-meta-*.tar.gz - docker-hub: name: Release on Docker Hub needs: - semantic-release if: needs.semantic-release.outputs.new-release-published == 'true' - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest + permissions: + id-token: write # This is required for requesting the JWT from AWS + contents: read + packages: write steps: - - uses: actions/checkout@v3 + - id: meta + uses: docker/metadata-action@v5 + with: + images: | + supabase/postgres-meta + public.ecr.aws/supabase/postgres-meta + ghcr.io/supabase/postgres-meta + tags: | + type=raw,value=v${{ needs.semantic-release.outputs.new-release-version }} - - uses: docker/setup-qemu-action@v1 + - uses: docker/setup-qemu-action@v3 with: platforms: amd64,arm64 + - uses: docker/setup-buildx-action@v3 - - uses: docker/setup-buildx-action@v1 - - - uses: docker/login-action@v1 + - name: Login to DockerHub + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - - uses: docker/build-push-action@v2 + - name: configure aws credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.PROD_AWS_ROLE }} + aws-region: us-east-1 + + - name: Login to ECR + uses: docker/login-action@v3 + with: + registry: public.ecr.aws + + - name: Login to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - uses: docker/build-push-action@v6 with: - context: . - platforms: linux/amd64,linux/arm64 push: true - tags: supabase/postgres-meta:latest,supabase/postgres-meta:v${{ needs.semantic-release.outputs.new-release-version }} + platforms: linux/amd64,linux/arm64 + tags: ${{ steps.meta.outputs.tags }} diff --git a/.gitignore b/.gitignore index 8d050113..7a26dfc4 100644 --- a/.gitignore +++ b/.gitignore @@ -73,6 +73,9 @@ typings/ .env .env.test +# sentry cli config +.sentryclirc + # parcel-bundler cache (https://parceljs.org/) .cache diff --git a/.kodiak.toml b/.kodiak.toml deleted file mode 100644 index 71c0b7ae..00000000 --- a/.kodiak.toml +++ /dev/null @@ -1,20 +0,0 @@ -version = 1 - -[update] -autoupdate_label = "dependencies" - -[approve] -auto_approve_usernames = ["dependabot"] - -[merge.automerge_dependencies] -versions = ["minor", "patch"] - -[merge] -automerge_label = "pr/automerge" -delete_branch_on_merge = true -# prefer rebase over merge commits -method = "rebase" -# this should make sure that the automerge label doesn't get removed -# hopefully, when dependabot resolves conflicts and pushes an update, -# kodiak will get triggered again and merge the PR -notify_on_conflict = false diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000..85aee5a5 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v20 \ No newline at end of file diff --git a/.pkg.config.json b/.pkg.config.json deleted file mode 100644 index fc41ced7..00000000 --- a/.pkg.config.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "@supabase/postgres-meta", - "bin": { - "postgres-meta": "bin/src/server/app.js" - }, - "pkg": { - "assets": ["bin/**/*.sql"], - "scripts": ["node_modules/pg-format/lib/reserved.js"] - } -} diff --git a/.releaserc.json b/.releaserc.json new file mode 100644 index 00000000..09b4ea86 --- /dev/null +++ b/.releaserc.json @@ -0,0 +1,13 @@ +{ + "plugins": [ + "@semantic-release/commit-analyzer", + "@semantic-release/release-notes-generator", + [ + "@semantic-release/github", { + "successComment": false, + "failTitle": false + } + ], + "@semantic-release/npm" + ] +} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..c7f56a71 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,14 @@ +# Contributing + +### Install deps + +- docker +- `npm install` + +### Start services + +1. Run `docker compose up` in `/test/db` +2. Run the tests: `npm run test:run` +3. Make changes in code (`/src`) and tests (`/test/lib` and `/test/server`) +4. Run the tests again: `npm run test:run` +5. Commit + PR \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 72b422da..8756b7ac 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,23 +1,23 @@ -FROM node:14-alpine as deps -RUN apk add --no-cache bash make git python3 -RUN apk add --update alpine-sdk +FROM node:20 as build WORKDIR /usr/src/app # Do `npm ci` separately so we can cache `node_modules` # https://nodejs.org/en/docs/guides/nodejs-docker-webapp/ -COPY package*.json ./ +COPY package.json package-lock.json ./ RUN npm clean-install - -FROM node:14-alpine as build -WORKDIR /usr/src/app -COPY --from=deps /usr/src/app/node_modules ./node_modules COPY . . -RUN npm run build:server +RUN npm run build && npm prune --omit=dev -FROM node:14-alpine as prod +FROM node:20-slim +RUN apt-get update && apt-get install -y \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* WORKDIR /usr/src/app -COPY --from=deps /usr/src/app/node_modules ./node_modules -COPY --from=build /usr/src/app/bin ./bin +COPY --from=build /usr/src/app/node_modules node_modules +COPY --from=build /usr/src/app/dist dist COPY package.json ./ ENV PG_META_PORT=8080 -CMD ["npm", "run", "start"] +# `npm run start` does not forward signals to child process +CMD ["node", "dist/server/server.js"] EXPOSE 8080 +# --start-period defaults to 0s, but can't be set to 0s (to be explicit) by now +HEALTHCHECK --interval=5s --timeout=5s --retries=3 CMD node -e "fetch('http://localhost:8080/health').then((r) => {if (r.status !== 200) throw new Error(r.status)})" diff --git a/README.md b/README.md index 06f900a0..da8c787d 100644 --- a/README.md +++ b/README.md @@ -67,12 +67,14 @@ Helpers: - [ ] `/generators` - [ ] GET `/openapi`: Generate Open API - [ ] GET `/typescript`: Generate Typescript types + - [ ] GET `/swift`: Generate Swift types (beta) ## Quickstart Set the following ENV VARS: ```bash +PG_META_HOST="0.0.0.0" PG_META_PORT=8080 PG_META_DB_HOST="postgres" PG_META_DB_NAME="postgres" @@ -83,11 +85,12 @@ PG_META_DB_PASSWORD="postgres" Then run any of the binaries in the releases. + ## FAQs **Why?** -This serves as a light-weight connection pooler. It also normalises the Postgres system catalog into a more readable format. While it it a lot of reinventing right now, this server will eventually provide helpers (such as type generators). The server is multi-tenant, so it can support multiple Postgres databases from a single server. +This serves as a light-weight connection pooler. It also normalises the Postgres system catalog into a more readable format. While there is a lot of re-inventing right now, this server will eventually provide helpers (such as type generators). The server is multi-tenant, so it can support multiple Postgres databases from a single server. **What security does this use?** @@ -97,7 +100,17 @@ None. Please don't use this as a standalone server. This should be used behind a To start developing, run `npm run dev`. It will set up the database with Docker for you. The server will restart on file change. -If you are fixing a bug, you should create a new test case. To test your changes, add the `-u/--updateSnapshot` flag to `jest` on the `test:run` script, run `npm run test`, and then review the git diff of the snapshots. Depending on your change, you may see `id` fields being changed - this is expected and you are free to commit it, as long as it passes the CI. Don't forget to remove the `-u/--updateSnapshot` flag when committing. +If you are fixing a bug, you should create a new test case. To test your changes, add the `-u` flag to `vitest` on the `test:run` script, run `npm run test`, and then review the git diff of the snapshots. Depending on your change, you may see `id` fields being changed - this is expected and you are free to commit it, as long as it passes the CI. Don't forget to remove the `-u` flag when committing. + +To make changes to the type generation, run `npm run gen:types:` while you have `npm run dev` running, +where `` is one of: + +- `typescript` +- `go` +- `swift` (beta) + +To use your own database connection string instead of the provided test database, run: +`PG_META_DB_URL=postgresql://postgres:postgres@localhost:5432/postgres npm run gen:types:` ## Licence @@ -108,3 +121,4 @@ Apache 2.0 We are building the features of Firebase using enterprise-grade, open source products. We support existing communities wherever possible, and if the products don’t exist we build them and open source them ourselves. [![New Sponsor](https://user-images.githubusercontent.com/10214025/90518111-e74bbb00-e198-11ea-8f88-c9e3c1aa4b5b.png)](https://github.com/sponsors/supabase) + diff --git a/jest.config.js b/jest.config.js deleted file mode 100644 index 2bd7f337..00000000 --- a/jest.config.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - preset: 'ts-jest', - testEnvironment: 'node', - testMatch: ['**/*.test.ts'] -} diff --git a/package-lock.json b/package-lock.json index ce3a055b..752051a3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,1516 +1,2669 @@ { "name": "@supabase/postgres-meta", "version": "0.0.0-automated", - "lockfileVersion": 1, + "lockfileVersion": 3, "requires": true, - "dependencies": { - "@babel/code-frame": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.0.tgz", - "integrity": "sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA==", - "dev": true, - "requires": { - "@babel/highlight": "^7.16.0" - } - }, - "@babel/compat-data": { - "version": "7.16.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.16.4.tgz", - "integrity": "sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q==", - "dev": true - }, - "@babel/core": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.5.tgz", - "integrity": "sha512-wUcenlLzuWMZ9Zt8S0KmFwGlH6QKRh3vsm/dhDA3CHkiTA45YuG1XkHRcNRl73EFPXDp/d5kVOU0/y7x2w6OaQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.16.0", - "@babel/generator": "^7.16.5", - "@babel/helper-compilation-targets": "^7.16.3", - "@babel/helper-module-transforms": "^7.16.5", - "@babel/helpers": "^7.16.5", - "@babel/parser": "^7.16.5", - "@babel/template": "^7.16.0", - "@babel/traverse": "^7.16.5", - "@babel/types": "^7.16.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0", - "source-map": "^0.5.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/generator": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.5.tgz", - "integrity": "sha512-kIvCdjZqcdKqoDbVVdt5R99icaRtrtYhYK/xux5qiWCBmfdvEYMFZ68QCrpE5cbFM1JsuArUNs1ZkuKtTtUcZA==", - "dev": true, - "requires": { - "@babel/types": "^7.16.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - }, + "packages": { + "": { + "name": "@supabase/postgres-meta", + "version": "0.0.0-automated", + "license": "MIT", "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/helper-compilation-targets": { - "version": "7.16.3", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.3.tgz", - "integrity": "sha512-vKsoSQAyBmxS35JUOOt+07cLc6Nk/2ljLIHwmq2/NM6hdioUaqEXq/S+nXvbvXbZkNDlWOymPanJGOc4CBjSJA==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.16.0", - "@babel/helper-validator-option": "^7.14.5", - "browserslist": "^4.17.5", - "semver": "^6.3.0" + "@fastify/cors": "^9.0.1", + "@fastify/swagger": "^8.2.1", + "@fastify/type-provider-typebox": "^3.5.0", + "@sentry/node": "^9.12.0", + "@sentry/profiling-node": "^9.12.0", + "@sinclair/typebox": "^0.31.25", + "close-with-grace": "^2.1.0", + "crypto-js": "^4.0.0", + "fastify": "^4.24.3", + "fastify-metrics": "^10.0.0", + "pg": "npm:@supabase/pg@0.0.3", + "pg-connection-string": "^2.7.0", + "pg-format": "^1.0.4", + "pg-protocol": "npm:@supabase/pg-protocol@0.0.2", + "pgsql-parser": "^13.16.0", + "pino": "^9.5.0", + "postgres-array": "^3.0.1", + "prettier": "^3.3.3", + "prettier-plugin-sql": "0.17.1" }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@babel/helper-environment-visitor": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.5.tgz", - "integrity": "sha512-ODQyc5AnxmZWm/R2W7fzhamOk1ey8gSguo5SGvF0zcB3uUzRpTRmM/jmLSm9bDMyPlvbyJ+PwPEK0BWIoZ9wjg==", - "dev": true, - "requires": { - "@babel/types": "^7.16.0" - } - }, - "@babel/helper-function-name": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.0.tgz", - "integrity": "sha512-BZh4mEk1xi2h4HFjWUXRQX5AEx4rvaZxHgax9gcjdLWdkjsY7MKt5p0otjsg5noXw+pB+clMCjw+aEVYADMjog==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.16.0", - "@babel/template": "^7.16.0", - "@babel/types": "^7.16.0" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.0.tgz", - "integrity": "sha512-ASCquNcywC1NkYh/z7Cgp3w31YW8aojjYIlNg4VeJiHkqyP4AzIvr4qx7pYDb4/s8YcsZWqqOSxgkvjUz1kpDQ==", - "dev": true, - "requires": { - "@babel/types": "^7.16.0" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.0.tgz", - "integrity": "sha512-1AZlpazjUR0EQZQv3sgRNfM9mEVWPK3M6vlalczA+EECcPz3XPh6VplbErL5UoMpChhSck5wAJHthlj1bYpcmg==", - "dev": true, - "requires": { - "@babel/types": "^7.16.0" - } - }, - "@babel/helper-module-imports": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.0.tgz", - "integrity": "sha512-kkH7sWzKPq0xt3H1n+ghb4xEMP8k0U7XV3kkB+ZGy69kDk2ySFW1qPi06sjKzFY3t1j6XbJSqr4mF9L7CYVyhg==", - "dev": true, - "requires": { - "@babel/types": "^7.16.0" + "devDependencies": { + "@types/crypto-js": "^4.1.1", + "@types/node": "^20.11.14", + "@types/pg": "^8.11.10", + "@types/pg-format": "^1.0.1", + "@vitest/coverage-v8": "^3.0.5", + "cpy-cli": "^5.0.0", + "nodemon": "^3.1.7", + "npm-run-all": "^4.1.5", + "pino-pretty": "^12.0.0", + "rimraf": "^6.0.1", + "ts-node": "^10.9.1", + "typescript": "^5.6.3", + "vitest": "^3.0.5" + }, + "engines": { + "node": ">=20", + "npm": ">=9" } }, - "@babel/helper-module-transforms": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.5.tgz", - "integrity": "sha512-CkvMxgV4ZyyioElFwcuWnDCcNIeyqTkCm9BxXZi73RR1ozqlpboqsbGUNvRTflgZtFbbJ1v5Emvm+lkjMYY/LQ==", + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, - "requires": { - "@babel/helper-environment-visitor": "^7.16.5", - "@babel/helper-module-imports": "^7.16.0", - "@babel/helper-simple-access": "^7.16.0", - "@babel/helper-split-export-declaration": "^7.16.0", - "@babel/helper-validator-identifier": "^7.15.7", - "@babel/template": "^7.16.0", - "@babel/traverse": "^7.16.5", - "@babel/types": "^7.16.0" + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" } }, - "@babel/helper-plugin-utils": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.5.tgz", - "integrity": "sha512-59KHWHXxVA9K4HNF4sbHCf+eJeFe0Te/ZFGqBT4OjXhrwvA04sGfaEGsVTdsjoszq0YTP49RC9UKe5g8uN2RwQ==", - "dev": true - }, - "@babel/helper-simple-access": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.0.tgz", - "integrity": "sha512-o1rjBT/gppAqKsYfUdfHq5Rk03lMQrkPHG1OWzHWpLgVXRH4HnMM9Et9CVdIqwkCQlobnGHEJMsgWP/jE1zUiw==", + "node_modules/@babel/helper-string-parser": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", "dev": true, - "requires": { - "@babel/types": "^7.16.0" + "license": "MIT", + "engines": { + "node": ">=6.9.0" } }, - "@babel/helper-split-export-declaration": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.0.tgz", - "integrity": "sha512-0YMMRpuDFNGTHNRiiqJX19GjNXA4H0E8jZ2ibccfSxaCogbm3am5WN/2nQNj0YnQwGWM1J06GOcQ2qnh3+0paw==", + "node_modules/@babel/helper-validator-identifier": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", "dev": true, - "requires": { - "@babel/types": "^7.16.0" + "license": "MIT", + "engines": { + "node": ">=6.9.0" } }, - "@babel/helper-validator-identifier": { - "version": "7.15.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", - "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", - "dev": true - }, - "@babel/helper-validator-option": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz", - "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==", - "dev": true - }, - "@babel/helpers": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.5.tgz", - "integrity": "sha512-TLgi6Lh71vvMZGEkFuIxzaPsyeYCHQ5jJOOX1f0xXn0uciFuE8cEk0wyBquMcCxBXZ5BJhE2aUB7pnWTD150Tw==", + "node_modules/@babel/parser": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz", + "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==", "dev": true, - "requires": { - "@babel/template": "^7.16.0", - "@babel/traverse": "^7.16.5", - "@babel/types": "^7.16.0" + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" } }, - "@babel/highlight": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.0.tgz", - "integrity": "sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g==", + "node_modules/@babel/types": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz", + "integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==", "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.15.7", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, + "license": "MIT", "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" } }, - "@babel/parser": { - "version": "7.16.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.6.tgz", - "integrity": "sha512-Gr86ujcNuPDnNOY8mi383Hvi8IYrJVJYuf3XcuBM/Dgd+bINn/7tHqsj+tKkoreMbmGsFLsltI/JJd8fOFWGDQ==", - "dev": true - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" + "license": "MIT", + "engines": { + "node": ">=18" } }, - "@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" } }, - "@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" } }, - "@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz", + "integrity": "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==", + "cpu": [ + "ppc64" + ], "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.1.tgz", + "integrity": "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.1.tgz", + "integrity": "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.1.tgz", + "integrity": "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.1.tgz", + "integrity": "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.1.tgz", + "integrity": "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.1.tgz", + "integrity": "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.1.tgz", + "integrity": "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.1.tgz", + "integrity": "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.1.tgz", + "integrity": "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.1.tgz", + "integrity": "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.1.tgz", + "integrity": "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.1.tgz", + "integrity": "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.1.tgz", + "integrity": "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.1.tgz", + "integrity": "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.1.tgz", + "integrity": "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.1.tgz", + "integrity": "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.1.tgz", + "integrity": "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.1.tgz", + "integrity": "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.1.tgz", + "integrity": "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.1.tgz", + "integrity": "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.1.tgz", + "integrity": "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.1.tgz", + "integrity": "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.1.tgz", + "integrity": "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.1.tgz", + "integrity": "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" } }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" + "node_modules/@fastify/ajv-compiler": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-3.6.0.tgz", + "integrity": "sha512-LwdXQJjmMD+GwLOkP7TVC68qa+pSSogeWWmznRJ/coyTcfe9qA05AHFSe1eZFwK6q+xVRpChnvFUkf1iYaSZsQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.11.0", + "ajv-formats": "^2.1.1", + "fast-uri": "^2.0.0" } }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "node_modules/@fastify/cors": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@fastify/cors/-/cors-9.0.1.tgz", + "integrity": "sha512-YY9Ho3ovI+QHIL2hW+9X4XqQjXLjJqsU+sMV/xFsxZkE8p3GNnYVFpoOxF7SsP5ZL76gwvbo3V9L+FIekBGU4Q==", + "license": "MIT", + "dependencies": { + "fastify-plugin": "^4.0.0", + "mnemonist": "0.39.6" } }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } + "node_modules/@fastify/error": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@fastify/error/-/error-3.4.1.tgz", + "integrity": "sha512-wWSvph+29GR783IhmvdwWnN4bUxTD01Vm5Xad4i7i1VuAOItLvbPAb69sb0IQ2N57yprvhNIwAP5B6xfKTmjmQ==", + "license": "MIT" }, - "@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "node_modules/@fastify/fast-json-stringify-compiler": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@fastify/fast-json-stringify-compiler/-/fast-json-stringify-compiler-4.3.0.tgz", + "integrity": "sha512-aZAXGYo6m22Fk1zZzEUKBvut/CIIQe/BapEORnxiD5Qr0kPHqqI69NtEMCme74h+at72sPhbkb4ZrLd1W3KRLA==", + "license": "MIT", + "dependencies": { + "fast-json-stringify": "^5.7.0" } }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" + "node_modules/@fastify/merge-json-schemas": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@fastify/merge-json-schemas/-/merge-json-schemas-0.1.1.tgz", + "integrity": "sha512-fERDVz7topgNjtXsJTTW1JKLy0rhuLRcquYqNR9rF7OcVpCa2OVW49ZPDIhaRRCaUuvVxI+N416xUoF76HNSXA==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" } }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" + "node_modules/@fastify/swagger": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/@fastify/swagger/-/swagger-8.15.0.tgz", + "integrity": "sha512-zy+HEEKFqPMS2sFUsQU5X0MHplhKJvWeohBwTCkBAJA/GDYGLGUWQaETEhptiqxK7Hs0fQB9B4MDb3pbwIiCwA==", + "license": "MIT", + "dependencies": { + "fastify-plugin": "^4.0.0", + "json-schema-resolver": "^2.0.0", + "openapi-types": "^12.0.0", + "rfdc": "^1.3.0", + "yaml": "^2.2.2" } }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" + "node_modules/@fastify/type-provider-typebox": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@fastify/type-provider-typebox/-/type-provider-typebox-3.6.0.tgz", + "integrity": "sha512-HTeOLvirfGg0u1KGao3iXn5rZpYNqlrOmyDnXSXAbWVPa+mDQTTBNs/x5uZzOB6vFAqr0Xcf7x1lxOamNSYKjw==", + "license": "MIT", + "peerDependencies": { + "@sinclair/typebox": ">=0.26 <=0.32" } }, - "@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } + "node_modules/@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "license": "MIT" }, - "@babel/plugin-syntax-typescript": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.5.tgz", - "integrity": "sha512-/d4//lZ1Vqb4mZ5xTep3dDK888j7BGM/iKqBmndBaoYAFPlPKrGU608VVBz5JeyAb6YQDjRu1UKqj86UhwWVgw==", + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.5" - } - }, - "@babel/runtime": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.5.tgz", - "integrity": "sha512-TXWihFIS3Pyv5hzR7j6ihmeLkZfrXGxAr5UfSl8CHf+6q/wpiYDkUau0czckpYG8QmnCIuPpdLtuA9VmuGGyMA==", - "requires": { - "regenerator-runtime": "^0.13.4" + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" } }, - "@babel/template": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.0.tgz", - "integrity": "sha512-MnZdpFD/ZdYhXwiunMqqgyZyucaYsbL0IrjoGjaVhGilz+x8YB++kRfygSOIj1yOtWKPlx7NBp+9I1RQSgsd5A==", + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, - "requires": { - "@babel/code-frame": "^7.16.0", - "@babel/parser": "^7.16.0", - "@babel/types": "^7.16.0" + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "@babel/traverse": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.5.tgz", - "integrity": "sha512-FOCODAzqUMROikDYLYxl4nmwiLlu85rNqBML/A5hKRVXG2LV8d0iMqgPzdYTcIpjZEBB7D6UDU9vxRZiriASdQ==", + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true, - "requires": { - "@babel/code-frame": "^7.16.0", - "@babel/generator": "^7.16.5", - "@babel/helper-environment-visitor": "^7.16.5", - "@babel/helper-function-name": "^7.16.0", - "@babel/helper-hoist-variables": "^7.16.0", - "@babel/helper-split-export-declaration": "^7.16.0", - "@babel/parser": "^7.16.5", - "@babel/types": "^7.16.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - } + "license": "MIT" }, - "@babel/types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.0.tgz", - "integrity": "sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg==", + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.15.7", - "to-fast-properties": "^2.0.0" + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "@fastify/ajv-compiler": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-1.1.0.tgz", - "integrity": "sha512-gvCOUNpXsWrIQ3A4aXCLIdblL0tDq42BG/2Xw7oxbil9h11uow10ztS2GuFazNBfjbrsZ5nl+nPl5jDSjj5TSg==", + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, - "requires": { - "ajv": "^6.12.6" - } - }, - "@gar/promisify": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", - "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==" - }, - "@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "requires": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "dependencies": { - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - } + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "@istanbuljs/schema": { + "node_modules/@istanbuljs/schema": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true - }, - "@jest/console": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.4.2.tgz", - "integrity": "sha512-xknHThRsPB/To1FUbi6pCe43y58qFC03zfb6R7fDb/FfC7k2R3i1l+izRBJf8DI46KhYGRaF14Eo9A3qbBoixg==", "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^27.4.2", - "jest-util": "^27.4.2", - "slash": "^3.0.0" - }, - "dependencies": { - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - } + "license": "MIT", + "engines": { + "node": ">=8" } }, - "@jest/core": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.4.5.tgz", - "integrity": "sha512-3tm/Pevmi8bDsgvo73nX8p/WPng6KWlCyScW10FPEoN1HU4pwI83tJ3TsFvi1FfzsjwUlMNEPowgb/rPau/LTQ==", + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", "dev": true, - "requires": { - "@jest/console": "^27.4.2", - "@jest/reporters": "^27.4.5", - "@jest/test-result": "^27.4.2", - "@jest/transform": "^27.4.5", - "@jest/types": "^27.4.2", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.8.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-changed-files": "^27.4.2", - "jest-config": "^27.4.5", - "jest-haste-map": "^27.4.5", - "jest-message-util": "^27.4.2", - "jest-regex-util": "^27.4.0", - "jest-resolve": "^27.4.5", - "jest-resolve-dependencies": "^27.4.5", - "jest-runner": "^27.4.5", - "jest-runtime": "^27.4.5", - "jest-snapshot": "^27.4.5", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.2", - "jest-watcher": "^27.4.2", - "micromatch": "^4.0.4", - "rimraf": "^3.0.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, + "license": "MIT", "dependencies": { - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - } - } - }, - "@jest/environment": { - "version": "27.4.4", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.4.4.tgz", - "integrity": "sha512-q+niMx7cJgt/t/b6dzLOh4W8Ef/8VyKG7hxASK39jakijJzbFBGpptx3RXz13FFV7OishQ9lTbv+dQ5K3EhfDQ==", - "dev": true, - "requires": { - "@jest/fake-timers": "^27.4.2", - "@jest/types": "^27.4.2", - "@types/node": "*", - "jest-mock": "^27.4.2" + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" } }, - "@jest/fake-timers": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.4.2.tgz", - "integrity": "sha512-f/Xpzn5YQk5adtqBgvw1V6bF8Nx3hY0OIRRpCvWcfPl0EAjdqWPdhH3t/3XpiWZqtjIEHDyMKP9ajpva1l4Zmg==", + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "@sinonjs/fake-timers": "^8.0.1", - "@types/node": "*", - "jest-message-util": "^27.4.2", - "jest-mock": "^27.4.2", - "jest-util": "^27.4.2" + "license": "MIT", + "engines": { + "node": ">=6.0.0" } }, - "@jest/globals": { - "version": "27.4.4", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.4.4.tgz", - "integrity": "sha512-bqpqQhW30BOreXM8bA8t8JbOQzsq/WnPTnBl+It3UxAD9J8yxEAaBEylHx1dtBapAr/UBk8GidXbzmqnee8tYQ==", + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, - "requires": { - "@jest/environment": "^27.4.4", - "@jest/types": "^27.4.2", - "expect": "^27.4.2" + "license": "MIT", + "engines": { + "node": ">=6.0.0" } }, - "@jest/reporters": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.4.5.tgz", - "integrity": "sha512-3orsG4vi8zXuBqEoy2LbnC1kuvkg1KQUgqNxmxpQgIOQEPeV0onvZu+qDQnEoX8qTQErtqn/xzcnbpeTuOLSiA==", + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "dev": true, - "requires": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^27.4.2", - "@jest/test-result": "^27.4.2", - "@jest/transform": "^27.4.5", - "@jest/types": "^27.4.2", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.2", - "graceful-fs": "^4.2.4", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^4.0.3", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "jest-haste-map": "^27.4.5", - "jest-resolve": "^27.4.5", - "jest-util": "^27.4.2", - "jest-worker": "^27.4.5", - "slash": "^3.0.0", - "source-map": "^0.6.0", - "string-length": "^4.0.1", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^8.1.0" - }, - "dependencies": { - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - } - } - }, - "@jest/source-map": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.4.0.tgz", - "integrity": "sha512-Ntjx9jzP26Bvhbm93z/AKcPRj/9wrkI88/gK60glXDx1q+IeI0rf7Lw2c89Ch6ofonB0On/iRDreQuQ6te9pgQ==", - "dev": true, - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.2.4", - "source-map": "^0.6.0" - } - }, - "@jest/test-result": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.4.2.tgz", - "integrity": "sha512-kr+bCrra9jfTgxHXHa2UwoQjxvQk3Am6QbpAiJ5x/50LW8llOYrxILkqY0lZRW/hu8FXesnudbql263+EW9iNA==", - "dev": true, - "requires": { - "@jest/console": "^27.4.2", - "@jest/types": "^27.4.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - } - }, - "@jest/test-sequencer": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.4.5.tgz", - "integrity": "sha512-n5woIn/1v+FT+9hniymHPARA9upYUmfi5Pw9ewVwXCDlK4F5/Gkees9v8vdjGdAIJ2MPHLHodiajLpZZanWzEQ==", - "dev": true, - "requires": { - "@jest/test-result": "^27.4.2", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.5", - "jest-runtime": "^27.4.5" - } - }, - "@jest/transform": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.4.5.tgz", - "integrity": "sha512-PuMet2UlZtlGzwc6L+aZmR3I7CEBpqadO03pU40l2RNY2fFJ191b9/ITB44LNOhVtsyykx0OZvj0PCyuLm7Eew==", - "dev": true, - "requires": { - "@babel/core": "^7.1.0", - "@jest/types": "^27.4.2", - "babel-plugin-istanbul": "^6.0.0", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.5", - "jest-regex-util": "^27.4.0", - "jest-util": "^27.4.2", - "micromatch": "^4.0.4", - "pirates": "^4.0.1", - "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" - }, - "dependencies": { - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - } - } + "license": "MIT" }, - "@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "@mapbox/node-pre-gyp": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.8.tgz", - "integrity": "sha512-CMGKi28CF+qlbXh26hDe6NxCd7amqeAzEqnS6IHeO6LoaKyM/n+Xw3HT1COdq8cuioOdlKdqn/hCmqPUOMOywg==", - "requires": { - "detect-libc": "^1.0.3", + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "license": "BSD-3-Clause", + "dependencies": { + "detect-libc": "^2.0.0", "https-proxy-agent": "^5.0.0", "make-dir": "^3.1.0", - "node-fetch": "^2.6.5", + "node-fetch": "^2.6.7", "nopt": "^5.0.0", "npmlog": "^5.0.1", "rimraf": "^3.0.2", "semver": "^7.3.5", "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "@nodelib/fs.scandir": { + "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" } }, - "@nodelib/fs.stat": { + "node_modules/@nodelib/fs.stat": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } }, - "@nodelib/fs.walk": { + "node_modules/@nodelib/fs.walk": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" } }, - "@npmcli/fs": { + "node_modules/@npmcli/fs": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", - "requires": { + "license": "ISC", + "dependencies": { "@gar/promisify": "^1.0.1", "semver": "^7.3.5" } }, - "@npmcli/move-file": { + "node_modules/@npmcli/move-file": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", - "requires": { + "deprecated": "This functionality has been moved to @npmcli/fs", + "license": "MIT", + "dependencies": { "mkdirp": "^1.0.4", "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=10" } }, - "@sinclair/typebox": { - "version": "0.23.4", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.23.4.tgz", - "integrity": "sha512-0/WqSvpVbCBAV1yPeko7eAczKbs78dNVAaX14quVlwOb2wxfKuXCx91h4NrEfkYK9zEnyVSW4JVI/trP3iS+Qg==" - }, - "@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", - "dev": true, - "requires": { - "type-detect": "4.0.8" + "node_modules/@npmcli/move-file/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "@sinonjs/fake-timers": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", - "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.7.0" + "node_modules/@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" } }, - "@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==" - }, - "@types/babel__core": { - "version": "7.1.17", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.17.tgz", - "integrity": "sha512-6zzkezS9QEIL8yCBvXWxPTJPNuMeECJVxSOhxNY/jfq9LxOTHivaYTqr37n9LknWWRTIkzqH2UilS5QFvfa90A==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" + "node_modules/@opentelemetry/api-logs": { + "version": "0.57.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.57.2.tgz", + "integrity": "sha512-uIX52NnTM0iBh84MShlpouI7UKqkZ7MrUszTmaypHBu4r7NofznSnQRfJ+uUeDtQDj6w8eFGg5KBLDAwAPz1+A==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=14" } }, - "@types/babel__generator": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.3.tgz", - "integrity": "sha512-/GWCmzJWqV7diQW54smJZzWbSFf4QYtF71WCKhcx6Ru/tFyQIY2eiiITcCAeuPbNSvT9YCGkVMqqvSk2Z0mXiA==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" + "node_modules/@opentelemetry/context-async-hooks": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-1.30.1.tgz", + "integrity": "sha512-s5vvxXPVdjqS3kTLKMeBMvop9hbWkwzBpu+mUO2M7sZtlkyDJGwFe33wRKnbaYDo8ExRVBIIdwIGrqpxHuKttA==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, - "@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" + "node_modules/@opentelemetry/core": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.30.1.tgz", + "integrity": "sha512-OOCM2C/QIURhJMuKaekP3TRBxBKxG/TWWA0TL2J6nXUtDnuCtccy49LUJF8xPFXMX+0LMcxFpCo8M9cGY1W6rQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "1.28.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, - "@types/babel__traverse": { - "version": "7.14.2", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz", - "integrity": "sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==", - "dev": true, - "requires": { - "@babel/types": "^7.3.0" + "node_modules/@opentelemetry/core/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.28.0.tgz", + "integrity": "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" } }, - "@types/crypto-js": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.1.1.tgz", - "integrity": "sha512-BG7fQKZ689HIoc5h+6D2Dgq1fABRa0RbBWKBd9SP/MVRVXROflpm5fhwyATX5duFmbStzyzyycPB8qUYKDH3NA==", - "dev": true - }, - "@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", - "dev": true, - "requires": { - "@types/node": "*" + "node_modules/@opentelemetry/instrumentation": { + "version": "0.57.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.57.2.tgz", + "integrity": "sha512-BdBGhQBh8IjZ2oIIX6F2/Q3LKm/FDDKi6ccYKcBTeilh6SNdNKveDOLk73BkSJjQLJk6qe4Yh+hHw1UPhCDdrg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.57.2", + "@types/shimmer": "^1.2.0", + "import-in-the-middle": "^1.8.1", + "require-in-the-middle": "^7.1.1", + "semver": "^7.5.2", + "shimmer": "^1.2.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" } }, - "@types/istanbul-lib-coverage": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", - "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", - "dev": true + "node_modules/@opentelemetry/instrumentation-amqplib": { + "version": "0.46.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-amqplib/-/instrumentation-amqplib-0.46.1.tgz", + "integrity": "sha512-AyXVnlCf/xV3K/rNumzKxZqsULyITJH6OVLiW6730JPRqWA7Zc9bvYoVNpN6iOpTU8CasH34SU/ksVJmObFibQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.57.1", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } }, - "@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*" + "node_modules/@opentelemetry/instrumentation-connect": { + "version": "0.43.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-connect/-/instrumentation-connect-0.43.1.tgz", + "integrity": "sha512-ht7YGWQuV5BopMcw5Q2hXn3I8eG8TH0J/kc/GMcW4CuNTgiP6wCu44BOnucJWL3CmFWaRHI//vWyAhaC8BwePw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.57.1", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@types/connect": "3.4.38" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" } }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" + "node_modules/@opentelemetry/instrumentation-dataloader": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-dataloader/-/instrumentation-dataloader-0.16.1.tgz", + "integrity": "sha512-K/qU4CjnzOpNkkKO4DfCLSQshejRNAJtd4esgigo/50nxCB6XCyi1dhAblUHM9jG5dRm8eu0FB+t87nIo99LYQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.57.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" } }, - "@types/jest": { - "version": "27.4.1", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.4.1.tgz", - "integrity": "sha512-23iPJADSmicDVrWk+HT58LMJtzLAnB2AgIzplQuq/bSrGaxCrlvRFjGbXmamnnk/mAmCdLStiGqggu28ocUyiw==", - "dev": true, - "requires": { - "jest-matcher-utils": "^27.0.0", - "pretty-format": "^27.0.0" + "node_modules/@opentelemetry/instrumentation-express": { + "version": "0.47.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-express/-/instrumentation-express-0.47.1.tgz", + "integrity": "sha512-QNXPTWteDclR2B4pDFpz0TNghgB33UMjUt14B+BZPmtH1MwUFAfLHBaP5If0Z5NZC+jaH8oF2glgYjrmhZWmSw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.57.1", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" } }, - "@types/minimist": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", - "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", - "dev": true - }, - "@types/node": { - "version": "17.0.22", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.22.tgz", - "integrity": "sha512-8FwbVoG4fy+ykY86XCAclKZDORttqE5/s7dyWZKLXTdv3vRy5HozBEinG5IqhvPXXzIZEcTVbuHlQEI6iuwcmw==", - "dev": true - }, - "@types/normalize-package-data": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", - "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", - "dev": true - }, - "@types/pg": { - "version": "8.6.5", - "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.6.5.tgz", - "integrity": "sha512-tOkGtAqRVkHa/PVZicq67zuujI4Oorfglsr2IbKofDwBSysnaqSx7W1mDqFqdkGE6Fbgh+PZAl0r/BWON/mozw==", - "dev": true, - "requires": { - "@types/node": "*", - "pg-protocol": "*", - "pg-types": "^2.2.0" + "node_modules/@opentelemetry/instrumentation-fastify": { + "version": "0.44.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-fastify/-/instrumentation-fastify-0.44.2.tgz", + "integrity": "sha512-arSp97Y4D2NWogoXRb8CzFK3W2ooVdvqRRtQDljFt9uC3zI6OuShgey6CVFC0JxT1iGjkAr1r4PDz23mWrFULQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.57.1", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" } }, - "@types/pg-format": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@types/pg-format/-/pg-format-1.0.2.tgz", - "integrity": "sha512-D3MEO6u3BObw3G4Xewjdx05MF5v/fiog78CedtrXe8BhONM8GvUz2dPfLWtI0BPRBoRd6anPHXe+sbrPReZouQ==", - "dev": true + "node_modules/@opentelemetry/instrumentation-fs": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-fs/-/instrumentation-fs-0.19.1.tgz", + "integrity": "sha512-6g0FhB3B9UobAR60BGTcXg4IHZ6aaYJzp0Ki5FhnxyAPt8Ns+9SSvgcrnsN2eGmk3RWG5vYycUGOEApycQL24A==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.57.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } }, - "@types/pino": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/@types/pino/-/pino-7.0.5.tgz", - "integrity": "sha512-wKoab31pknvILkxAF8ss+v9iNyhw5Iu/0jLtRkUD74cNfOOLJNnqfFKAv0r7wVaTQxRZtWrMpGfShwwBjOcgcg==", - "dev": true, - "requires": { - "pino": "*" + "node_modules/@opentelemetry/instrumentation-generic-pool": { + "version": "0.43.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-generic-pool/-/instrumentation-generic-pool-0.43.1.tgz", + "integrity": "sha512-M6qGYsp1cURtvVLGDrPPZemMFEbuMmCXgQYTReC/IbimV5sGrLBjB+/hANUpRZjX67nGLdKSVLZuQQAiNz+sww==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.57.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" } }, - "@types/prettier": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.2.tgz", - "integrity": "sha512-ekoj4qOQYp7CvjX8ZDBgN86w3MqQhLE1hczEJbEIjgFEumDy+na/4AJAbLXfgEWFNB2pKadM5rPFtuSGMWK7xA==", - "dev": true + "node_modules/@opentelemetry/instrumentation-graphql": { + "version": "0.47.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-graphql/-/instrumentation-graphql-0.47.1.tgz", + "integrity": "sha512-EGQRWMGqwiuVma8ZLAZnExQ7sBvbOx0N/AE/nlafISPs8S+QtXX+Viy6dcQwVWwYHQPAcuY3bFt3xgoAwb4ZNQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.57.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } }, - "@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true + "node_modules/@opentelemetry/instrumentation-hapi": { + "version": "0.45.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-hapi/-/instrumentation-hapi-0.45.2.tgz", + "integrity": "sha512-7Ehow/7Wp3aoyCrZwQpU7a2CnoMq0XhIcioFuKjBb0PLYfBfmTsFTUyatlHu0fRxhwcRsSQRTvEhmZu8CppBpQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.57.1", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } }, - "@types/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-FKjsOVbC6B7bdSB5CuzyHCkK69I=", - "dev": true + "node_modules/@opentelemetry/instrumentation-http": { + "version": "0.57.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-http/-/instrumentation-http-0.57.2.tgz", + "integrity": "sha512-1Uz5iJ9ZAlFOiPuwYg29Bf7bJJc/GeoeJIFKJYQf67nTVKFe8RHbEtxgkOmK4UGZNHKXcpW4P8cWBYzBn1USpg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.30.1", + "@opentelemetry/instrumentation": "0.57.2", + "@opentelemetry/semantic-conventions": "1.28.0", + "forwarded-parse": "2.1.2", + "semver": "^7.5.2" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-http/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.28.0.tgz", + "integrity": "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } }, - "@types/strip-json-comments": { - "version": "0.0.30", - "resolved": "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz", - "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", - "dev": true + "node_modules/@opentelemetry/instrumentation-ioredis": { + "version": "0.47.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-ioredis/-/instrumentation-ioredis-0.47.1.tgz", + "integrity": "sha512-OtFGSN+kgk/aoKgdkKQnBsQFDiG8WdCxu+UrHr0bXScdAmtSzLSraLo7wFIb25RVHfRWvzI5kZomqJYEg/l1iA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.57.1", + "@opentelemetry/redis-common": "^0.36.2", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "node_modules/@opentelemetry/instrumentation-kafkajs": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-kafkajs/-/instrumentation-kafkajs-0.7.1.tgz", + "integrity": "sha512-OtjaKs8H7oysfErajdYr1yuWSjMAectT7Dwr+axIoZqT9lmEOkD/H/3rgAs8h/NIuEi2imSXD+vL4MZtOuJfqQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.57.1", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-knex": { + "version": "0.44.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-knex/-/instrumentation-knex-0.44.1.tgz", + "integrity": "sha512-U4dQxkNhvPexffjEmGwCq68FuftFK15JgUF05y/HlK3M6W/G2iEaACIfXdSnwVNe9Qh0sPfw8LbOPxrWzGWGMQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.57.1", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-koa": { + "version": "0.47.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-koa/-/instrumentation-koa-0.47.1.tgz", + "integrity": "sha512-l/c+Z9F86cOiPJUllUCt09v+kICKvT+Vg1vOAJHtHPsJIzurGayucfCMq2acd/A/yxeNWunl9d9eqZ0G+XiI6A==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.57.1", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-lru-memoizer": { + "version": "0.44.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-lru-memoizer/-/instrumentation-lru-memoizer-0.44.1.tgz", + "integrity": "sha512-5MPkYCvG2yw7WONEjYj5lr5JFehTobW7wX+ZUFy81oF2lr9IPfZk9qO+FTaM0bGEiymwfLwKe6jE15nHn1nmHg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.57.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-mongodb": { + "version": "0.52.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongodb/-/instrumentation-mongodb-0.52.0.tgz", + "integrity": "sha512-1xmAqOtRUQGR7QfJFfGV/M2kC7wmI2WgZdpru8hJl3S0r4hW0n3OQpEHlSGXJAaNFyvT+ilnwkT+g5L4ljHR6g==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.57.1", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-mongoose": { + "version": "0.46.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongoose/-/instrumentation-mongoose-0.46.1.tgz", + "integrity": "sha512-3kINtW1LUTPkiXFRSSBmva1SXzS/72we/jL22N+BnF3DFcoewkdkHPYOIdAAk9gSicJ4d5Ojtt1/HeibEc5OQg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.57.1", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-mysql": { + "version": "0.45.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mysql/-/instrumentation-mysql-0.45.1.tgz", + "integrity": "sha512-TKp4hQ8iKQsY7vnp/j0yJJ4ZsP109Ht6l4RHTj0lNEG1TfgTrIH5vJMbgmoYXWzNHAqBH2e7fncN12p3BP8LFg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.57.1", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@types/mysql": "2.15.26" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-mysql2": { + "version": "0.45.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mysql2/-/instrumentation-mysql2-0.45.2.tgz", + "integrity": "sha512-h6Ad60FjCYdJZ5DTz1Lk2VmQsShiViKe0G7sYikb0GHI0NVvApp2XQNRHNjEMz87roFttGPLHOYVPlfy+yVIhQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.57.1", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@opentelemetry/sql-common": "^0.40.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-pg": { + "version": "0.51.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-pg/-/instrumentation-pg-0.51.1.tgz", + "integrity": "sha512-QxgjSrxyWZc7Vk+qGSfsejPVFL1AgAJdSBMYZdDUbwg730D09ub3PXScB9d04vIqPriZ+0dqzjmQx0yWKiCi2Q==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^1.26.0", + "@opentelemetry/instrumentation": "^0.57.1", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@opentelemetry/sql-common": "^0.40.1", + "@types/pg": "8.6.1", + "@types/pg-pool": "2.0.6" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-pg/node_modules/@types/pg": { + "version": "8.6.1", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.6.1.tgz", + "integrity": "sha512-1Kc4oAGzAl7uqUStZCDvaLFqZrW9qWSjXOmBfdgyBP5La7Us6Mg4GBvRlSoaZMhQF/zSj1C8CtKMBkoiT8eL8w==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^2.2.0" + } + }, + "node_modules/@opentelemetry/instrumentation-pg/node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@opentelemetry/instrumentation-pg/node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@opentelemetry/instrumentation-pg/node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@opentelemetry/instrumentation-pg/node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@opentelemetry/instrumentation-pg/node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@opentelemetry/instrumentation-redis-4": { + "version": "0.46.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-redis-4/-/instrumentation-redis-4-0.46.1.tgz", + "integrity": "sha512-UMqleEoabYMsWoTkqyt9WAzXwZ4BlFZHO40wr3d5ZvtjKCHlD4YXLm+6OLCeIi/HkX7EXvQaz8gtAwkwwSEvcQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.57.1", + "@opentelemetry/redis-common": "^0.36.2", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-tedious": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-tedious/-/instrumentation-tedious-0.18.1.tgz", + "integrity": "sha512-5Cuy/nj0HBaH+ZJ4leuD7RjgvA844aY2WW+B5uLcWtxGjRZl3MNLuxnNg5DYWZNPO+NafSSnra0q49KWAHsKBg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.57.1", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@types/tedious": "^4.0.14" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-undici": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-undici/-/instrumentation-undici-0.10.1.tgz", + "integrity": "sha512-rkOGikPEyRpMCmNu9AQuV5dtRlDmJp2dK5sw8roVshAGoB6hH/3QjDtRhdwd75SsJwgynWUNRUYe0wAkTo16tQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.57.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.7.0" + } + }, + "node_modules/@opentelemetry/redis-common": { + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/redis-common/-/redis-common-0.36.2.tgz", + "integrity": "sha512-faYX1N0gpLhej/6nyp6bgRjzAKXn5GOEMYY7YhciSfCoITAktLUtQ36d24QEWNA1/WA1y6qQunCe0OhHRkVl9g==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/resources": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.30.1.tgz", + "integrity": "sha512-5UxZqiAgLYGFjS4s9qm5mBVo433u+dSPUFWVWXmLAD4wB65oMCoXaJP1KJa9DIYYMeHu3z4BZcStG3LC593cWA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.30.1", + "@opentelemetry/semantic-conventions": "1.28.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/resources/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.28.0.tgz", + "integrity": "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/sdk-trace-base": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.30.1.tgz", + "integrity": "sha512-jVPgBbH1gCy2Lb7X0AVQ8XAfgg0pJ4nvl8/IiQA6nxOsPvS+0zMJaFSs2ltXe0J6C8dqjcnpyqINDJmU30+uOg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.30.1", + "@opentelemetry/resources": "1.30.1", + "@opentelemetry/semantic-conventions": "1.28.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-base/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.28.0.tgz", + "integrity": "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.32.0.tgz", + "integrity": "sha512-s0OpmpQFSfMrmedAn9Lhg4KWJELHCU6uU9dtIJ28N8UGhf9Y55im5X8fEzwhwDwiSqN+ZPSNrDJF7ivf/AuRPQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/sql-common": { + "version": "0.40.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sql-common/-/sql-common-0.40.1.tgz", + "integrity": "sha512-nSDlnHSqzC3pXn/wZEZVLuAuJ1MYMXPBwtv2qAbCa3847SaHItdE7SzUq/Jtb0KZmh1zfAbNi3AAMjztTT4Ugg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^1.1.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0" + } + }, + "node_modules/@pgsql/types": { + "version": "13.9.0", + "resolved": "https://registry.npmjs.org/@pgsql/types/-/types-13.9.0.tgz", + "integrity": "sha512-R26mn0zMkwfR8imEQ1Q4NedHwG9gTUfgVnLJUBqPn33JyhOUi2H6iEVTcC9kHAm7gQGpwSBKfuCItWgenAlm9g==", + "license": "SEE LICENSE IN LICENSE" + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, - "requires": { - "@types/yargs-parser": "*" + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" } }, - "@types/yargs-parser": { - "version": "20.2.1", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", - "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", - "dev": true + "node_modules/@prisma/instrumentation": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@prisma/instrumentation/-/instrumentation-6.5.0.tgz", + "integrity": "sha512-morJDtFRoAp5d/KENEm+K6Y3PQcn5bCvpJ5a9y3V3DNMrNy/ZSn2zulPGj+ld+Xj2UYVoaMJ8DpBX/o6iF6OiA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.52.0 || ^0.53.0 || ^0.54.0 || ^0.55.0 || ^0.56.0 || ^0.57.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.8" + } }, - "abab": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", - "dev": true + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.37.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.37.0.tgz", + "integrity": "sha512-l7StVw6WAa8l3vA1ov80jyetOAEo1FtHvZDbzXDO/02Sq/QVvqlHkYoFwDJPIMj0GKiistsBudfx5tGFnwYWDQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.37.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.37.0.tgz", + "integrity": "sha512-6U3SlVyMxezt8Y+/iEBcbp945uZjJwjZimu76xoG7tO1av9VO691z8PkhzQ85ith2I8R2RddEPeSfcbyPfD4hA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.37.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.37.0.tgz", + "integrity": "sha512-+iTQ5YHuGmPt10NTzEyMPbayiNTcOZDWsbxZYR1ZnmLnZxG17ivrPSWFO9j6GalY0+gV3Jtwrrs12DBscxnlYA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.37.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.37.0.tgz", + "integrity": "sha512-m8W2UbxLDcmRKVjgl5J/k4B8d7qX2EcJve3Sut7YGrQoPtCIQGPH5AMzuFvYRWZi0FVS0zEY4c8uttPfX6bwYQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.37.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.37.0.tgz", + "integrity": "sha512-FOMXGmH15OmtQWEt174v9P1JqqhlgYge/bUjIbiVD1nI1NeJ30HYT9SJlZMqdo1uQFyt9cz748F1BHghWaDnVA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.37.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.37.0.tgz", + "integrity": "sha512-SZMxNttjPKvV14Hjck5t70xS3l63sbVwl98g3FlVVx2YIDmfUIy29jQrsw06ewEYQ8lQSuY9mpAPlmgRD2iSsA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.37.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.37.0.tgz", + "integrity": "sha512-hhAALKJPidCwZcj+g+iN+38SIOkhK2a9bqtJR+EtyxrKKSt1ynCBeqrQy31z0oWU6thRZzdx53hVgEbRkuI19w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.37.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.37.0.tgz", + "integrity": "sha512-jUb/kmn/Gd8epbHKEqkRAxq5c2EwRt0DqhSGWjPFxLeFvldFdHQs/n8lQ9x85oAeVb6bHcS8irhTJX2FCOd8Ag==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.37.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.37.0.tgz", + "integrity": "sha512-oNrJxcQT9IcbcmKlkF+Yz2tmOxZgG9D9GRq+1OE6XCQwCVwxixYAa38Z8qqPzQvzt1FCfmrHX03E0pWoXm1DqA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.37.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.37.0.tgz", + "integrity": "sha512-pfxLBMls+28Ey2enpX3JvjEjaJMBX5XlPCZNGxj4kdJyHduPBXtxYeb8alo0a7bqOoWZW2uKynhHxF/MWoHaGQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.37.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.37.0.tgz", + "integrity": "sha512-yCE0NnutTC/7IGUq/PUHmoeZbIwq3KRh02e9SfFh7Vmc1Z7atuJRYWhRME5fKgT8aS20mwi1RyChA23qSyRGpA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.37.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.37.0.tgz", + "integrity": "sha512-NxcICptHk06E2Lh3a4Pu+2PEdZ6ahNHuK7o6Np9zcWkrBMuv21j10SQDJW3C9Yf/A/P7cutWoC/DptNLVsZ0VQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.37.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.37.0.tgz", + "integrity": "sha512-PpWwHMPCVpFZLTfLq7EWJWvrmEuLdGn1GMYcm5MV7PaRgwCEYJAwiN94uBuZev0/J/hFIIJCsYw4nLmXA9J7Pw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.37.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.37.0.tgz", + "integrity": "sha512-DTNwl6a3CfhGTAOYZ4KtYbdS8b+275LSLqJVJIrPa5/JuIufWWZ/QFvkxp52gpmguN95eujrM68ZG+zVxa8zHA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.37.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.37.0.tgz", + "integrity": "sha512-hZDDU5fgWvDdHFuExN1gBOhCuzo/8TMpidfOR+1cPZJflcEzXdCy1LjnklQdW8/Et9sryOPJAKAQRw8Jq7Tg+A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.37.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.37.0.tgz", + "integrity": "sha512-pKivGpgJM5g8dwj0ywBwe/HeVAUSuVVJhUTa/URXjxvoyTT/AxsLTAbkHkDHG7qQxLoW2s3apEIl26uUe08LVQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.37.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.37.0.tgz", + "integrity": "sha512-E2lPrLKE8sQbY/2bEkVTGDEk4/49UYRVWgj90MY8yPjpnGBQ+Xi1Qnr7b7UIWw1NOggdFQFOLZ8+5CzCiz143w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.37.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.37.0.tgz", + "integrity": "sha512-Jm7biMazjNzTU4PrQtr7VS8ibeys9Pn29/1bm4ph7CP2kf21950LgN+BaE2mJ1QujnvOc6p54eWWiVvn05SOBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.37.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.37.0.tgz", + "integrity": "sha512-e3/1SFm1OjefWICB2Ucstg2dxYDkDTZGDYgwufcbsxTHyqQps1UQf33dFEChBNmeSsTOyrjw2JJq0zbG5GF6RA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.37.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.37.0.tgz", + "integrity": "sha512-LWbXUBwn/bcLx2sSsqy7pK5o+Nr+VCoRoAohfJ5C/aBio9nfJmGQqHAhU6pwxV/RmyTk5AqdySma7uwWGlmeuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sentry-internal/node-cpu-profiler": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/node-cpu-profiler/-/node-cpu-profiler-2.1.0.tgz", + "integrity": "sha512-/gPj8ARZ8Jw8gCQWToCiUyLoOxBDP8wuFNx07mAXegYiDa4NcIvo37ZzDWaTG+wjwa/LvCpHxHff6pejt4KOKg==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.3", + "node-abi": "^3.73.0" + }, + "engines": { + "node": ">=18" + } }, - "abbrev": { + "node_modules/@sentry/core": { + "version": "9.12.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-9.12.0.tgz", + "integrity": "sha512-jOqQK/90uzHmsBvkPTj/DAEFvA5poX4ZRyC7LE1zjg4F5jdOp3+M4W3qCy0CkSTu88Zu5VWBoppCU2Bs34XEqg==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@sentry/node": { + "version": "9.12.0", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-9.12.0.tgz", + "integrity": "sha512-NZHneJovlLOdde85vJAIs7vIki36EfJ234d6YXHUE+874sxKMknB/wrzAZi5XS5nqT3kqIXD5KgjgDTjrhAENQ==", + "license": "MIT", + "dependencies": { + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/context-async-hooks": "^1.30.1", + "@opentelemetry/core": "^1.30.1", + "@opentelemetry/instrumentation": "^0.57.2", + "@opentelemetry/instrumentation-amqplib": "^0.46.1", + "@opentelemetry/instrumentation-connect": "0.43.1", + "@opentelemetry/instrumentation-dataloader": "0.16.1", + "@opentelemetry/instrumentation-express": "0.47.1", + "@opentelemetry/instrumentation-fastify": "0.44.2", + "@opentelemetry/instrumentation-fs": "0.19.1", + "@opentelemetry/instrumentation-generic-pool": "0.43.1", + "@opentelemetry/instrumentation-graphql": "0.47.1", + "@opentelemetry/instrumentation-hapi": "0.45.2", + "@opentelemetry/instrumentation-http": "0.57.2", + "@opentelemetry/instrumentation-ioredis": "0.47.1", + "@opentelemetry/instrumentation-kafkajs": "0.7.1", + "@opentelemetry/instrumentation-knex": "0.44.1", + "@opentelemetry/instrumentation-koa": "0.47.1", + "@opentelemetry/instrumentation-lru-memoizer": "0.44.1", + "@opentelemetry/instrumentation-mongodb": "0.52.0", + "@opentelemetry/instrumentation-mongoose": "0.46.1", + "@opentelemetry/instrumentation-mysql": "0.45.1", + "@opentelemetry/instrumentation-mysql2": "0.45.2", + "@opentelemetry/instrumentation-pg": "0.51.1", + "@opentelemetry/instrumentation-redis-4": "0.46.1", + "@opentelemetry/instrumentation-tedious": "0.18.1", + "@opentelemetry/instrumentation-undici": "0.10.1", + "@opentelemetry/resources": "^1.30.1", + "@opentelemetry/sdk-trace-base": "^1.30.1", + "@opentelemetry/semantic-conventions": "^1.30.0", + "@prisma/instrumentation": "6.5.0", + "@sentry/core": "9.12.0", + "@sentry/opentelemetry": "9.12.0", + "import-in-the-middle": "^1.13.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@sentry/opentelemetry": { + "version": "9.12.0", + "resolved": "https://registry.npmjs.org/@sentry/opentelemetry/-/opentelemetry-9.12.0.tgz", + "integrity": "sha512-jQfI/UmgDDbcWY439r1Jz0Y4mqNn3a2JwruWfCHWzIqQMOgBzkzcp9lbZMx9iU+x1iZTTp9s80Dy5F9nG4KKMQ==", + "license": "MIT", + "dependencies": { + "@sentry/core": "9.12.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/context-async-hooks": "^1.30.1", + "@opentelemetry/core": "^1.30.1", + "@opentelemetry/instrumentation": "^0.57.1", + "@opentelemetry/sdk-trace-base": "^1.30.1", + "@opentelemetry/semantic-conventions": "^1.28.0" + } + }, + "node_modules/@sentry/profiling-node": { + "version": "9.12.0", + "resolved": "https://registry.npmjs.org/@sentry/profiling-node/-/profiling-node-9.12.0.tgz", + "integrity": "sha512-ZAOmeytFDDfx5nqsImFoQmFhJFDzRxygyApKfK/5Ap42hDa4TKyZTxzHykVxgGhzMlnjxQv7XU7sAbpwZGzsSw==", + "license": "MIT", + "dependencies": { + "@sentry-internal/node-cpu-profiler": "^2.0.0", + "@sentry/core": "9.12.0", + "@sentry/node": "9.12.0" + }, + "bin": { + "sentry-prune-profiler-binaries": "scripts/prune-profiler-binaries.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.31.28", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.31.28.tgz", + "integrity": "sha512-/s55Jujywdw/Jpan+vsy6JZs1z2ZTGxTmbZTPiuSL2wz9mfzA2gN1zzaqmvfi4pq+uOt7Du85fkiwv5ymW84aQ==", + "license": "MIT" + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, + "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/@types/crypto-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.2.2.tgz", + "integrity": "sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mysql": { + "version": "2.15.26", + "resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.26.tgz", + "integrity": "sha512-DSLCOXhkvfS5WNNPbfn2KdICAmk8lLc+/PNvnPnF7gOdMZCxopXduqv0OQ13y/yA/zXTSikZZqVgybUxOEg6YQ==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "20.17.28", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.28.tgz", + "integrity": "sha512-DHlH/fNL6Mho38jTy7/JT7sn2wnXI+wULR6PV4gy4VHLVvnrV/d3pHAMQHhc4gjdLmK2ZiPoMxzp6B3yRajLSQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/@types/pg": { + "version": "8.11.11", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.11.11.tgz", + "integrity": "sha512-kGT1qKM8wJQ5qlawUrEkXgvMSXoV213KfMGXcwfDwUIfUHXqXYXOfS1nE1LINRJVVVx5wCm70XnFlMHaIcQAfw==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^4.0.1" + } + }, + "node_modules/@types/pg-format": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/pg-format/-/pg-format-1.0.5.tgz", + "integrity": "sha512-i+oEEJEC+1I3XAhgqtVp45Faj8MBbV0Aoq4rHsHD7avgLjyDkaWKObd514g0Q/DOUkdxU0P4CQ0iq2KR4SoJcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/pg-pool": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/pg-pool/-/pg-pool-2.0.6.tgz", + "integrity": "sha512-TaAUE5rq2VQYxab5Ts7WZhKNmuN78Q6PiFonTDdpbx8a1H0M1vhy3rhiMjl+e2iHmogyMw7jZF4FrE6eJUy5HQ==", + "license": "MIT", + "dependencies": { + "@types/pg": "*" + } + }, + "node_modules/@types/shimmer": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@types/shimmer/-/shimmer-1.2.0.tgz", + "integrity": "sha512-UE7oxhQLLd9gub6JKIAhDq06T0F6FnztwMNRvYgjeQSBeMc1ZG/tA47EwfduvkuQS8apbkM/lpLpWsaCeYsXVg==", + "license": "MIT" + }, + "node_modules/@types/tedious": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/@types/tedious/-/tedious-4.0.14.tgz", + "integrity": "sha512-KHPsfX/FoVbUGbyYvk1q9MMQHLPeRZhRJZdO45Q4YjvFkv4hMNghCWTvy7rdKessBsmtz4euWCWAB6/tVpI1Iw==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@vitest/coverage-v8": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-3.0.9.tgz", + "integrity": "sha512-15OACZcBtQ34keIEn19JYTVuMFTlFrClclwWjHo/IRPg/8ELpkgNTl0o7WLP9WO9XGH6+tip9CPYtEOrIDJvBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.3.0", + "@bcoe/v8-coverage": "^1.0.2", + "debug": "^4.4.0", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-lib-source-maps": "^5.0.6", + "istanbul-reports": "^3.1.7", + "magic-string": "^0.30.17", + "magicast": "^0.3.5", + "std-env": "^3.8.0", + "test-exclude": "^7.0.1", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "3.0.9", + "vitest": "3.0.9" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } + } + }, + "node_modules/@vitest/expect": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.0.9.tgz", + "integrity": "sha512-5eCqRItYgIML7NNVgJj6TVCmdzE7ZVgJhruW0ziSQV4V7PvLkDL1bBkBdcTs/VuIz0IxPb5da1IDSqc1TR9eig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "3.0.9", + "@vitest/utils": "3.0.9", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.0.9.tgz", + "integrity": "sha512-ryERPIBOnvevAkTq+L1lD+DTFBRcjueL9lOUfXsLfwP92h4e+Heb+PjiqS3/OURWPtywfafK0kj++yDFjWUmrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "3.0.9", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.0.9.tgz", + "integrity": "sha512-OW9F8t2J3AwFEwENg3yMyKWweF7oRJlMyHOMIhO5F3n0+cgQAJZBjNgrF8dLwFTEXl5jUqBLXd9QyyKv8zEcmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.0.9.tgz", + "integrity": "sha512-NX9oUXgF9HPfJSwl8tUZCMP1oGx2+Sf+ru6d05QjzQz4OwWg0psEzwY6VexP2tTHWdOkhKHUIZH+fS6nA7jfOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "3.0.9", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.0.9.tgz", + "integrity": "sha512-AiLUiuZ0FuA+/8i19mTYd+re5jqjEc2jZbgJ2up0VY0Ddyyxg/uUtBDpIFAy4uzKaQxOW8gMgBdAJJ2ydhu39A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.0.9", + "magic-string": "^0.30.17", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.0.9.tgz", + "integrity": "sha512-/CcK2UDl0aQ2wtkp3YVWldrpLRNCfVcIOFGlVGKO4R5eajsH393Z1yiXLVQ7vWsj26JOEjeZI0x5sm5P4OGUNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^3.0.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.0.9.tgz", + "integrity": "sha512-ilHM5fHhZ89MCp5aAaM9uhfl1c2JdxVxl3McqsdVyVNN6JffnEen8UMCdRTzOhGXNQGo5GNL9QugHrz727Wnng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.0.9", + "loupe": "^3.1.3", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "license": "ISC" }, - "abstract-logging": { + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/abstract-logging": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz", "integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==", - "dev": true + "license": "MIT" + }, + "node_modules/acorn": { + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } }, - "acorn": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.6.0.tgz", - "integrity": "sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==", - "dev": true + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "license": "MIT", + "peerDependencies": { + "acorn": "^8" + } }, - "acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", "dev": true, - "requires": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" - }, + "license": "MIT", "dependencies": { - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true - } + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" } }, - "acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true - }, - "agent-base": { + "node_modules/agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "requires": { + "license": "MIT", + "dependencies": { "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" } }, - "agentkeepalive": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz", - "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==", - "requires": { - "debug": "^4.1.0", - "depd": "^1.1.2", + "node_modules/agentkeepalive": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "license": "MIT", + "dependencies": { "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" } }, - "aggregate-error": { + "node_modules/aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "requires": { + "license": "MIT", + "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "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" } }, - "ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "requires": { - "type-fest": "^0.21.3" + "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" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } } }, - "ansi-regex": { + "node_modules/ajv/node_modules/fast-uri": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", + "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "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==" + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, - "requires": { - "color-convert": "^2.0.1" + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" } }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, - "requires": { + "license": "ISC", + "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" } }, - "aproba": { + "node_modules/aproba": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "license": "ISC" }, - "archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", - "dev": true - }, - "are-we-there-yet": { + "node_modules/are-we-there-yet": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", - "requires": { + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { "delegates": "^1.0.0", "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" } }, - "arg": { + "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true + "dev": true, + "license": "MIT" }, - "argparse": { + "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==" + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "args": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/args/-/args-5.0.1.tgz", - "integrity": "sha512-1kqmFCFsPffavQFGt8OxJdIcETti99kySRUPMpOhaGjL6mRJn8HFU1OxKY5bMqfZKUwTQc1mZkAjmGYaVOHFtQ==", - "dev": true, - "requires": { - "camelcase": "5.0.0", - "chalk": "2.4.2", - "leven": "2.1.0", - "mri": "1.1.4" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "camelcase": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz", - "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==", - "dev": true - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "leven": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", - "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "arrify": { + "node_modules/arrify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/arrify/-/arrify-3.0.0.tgz", "integrity": "sha512-tLkvA81vQG/XqE2mjDkGQHoOINtMHtysSnemrmoGe6PydDPMRbVugqyk4A6V/WDWEfm3l+0d8anA9r8cv/5Jaw==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } }, - "at-least-node": { + "node_modules/async-function": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } }, - "atomic-sleep": { + "node_modules/atomic-sleep": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", - "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==" - }, - "avvio": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/avvio/-/avvio-7.2.2.tgz", - "integrity": "sha512-XW2CMCmZaCmCCsIaJaLKxAzPwF37fXi1KGxNOvedOpeisLdmxZnblGc3hpHWYnlP+KOUxZsazh43WXNHgXpbqw==", - "dev": true, - "requires": { - "archy": "^1.0.0", - "debug": "^4.0.0", - "fastq": "^1.6.1", - "queue-microtask": "^1.1.2" - } - }, - "aws-sdk": { - "version": "2.1095.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1095.0.tgz", - "integrity": "sha512-OrZq2pTDsnfOJYsAdRlw+NXTGLQYqWldSZR3HugW8JT4JPWyFZrgB2yPP2ElFHX+4J4SZg5QvkAXl/7s9gLTgA==", - "requires": { - "buffer": "4.9.2", - "events": "1.1.1", - "ieee754": "1.1.13", - "jmespath": "0.16.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "uuid": "3.3.2", - "xml2js": "0.4.19" - }, - "dependencies": { - "buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, - "ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" - }, - "jmespath": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", - "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==" - }, - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" - } + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" } }, - "babel-jest": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.4.5.tgz", - "integrity": "sha512-3uuUTjXbgtODmSv/DXO9nZfD52IyC2OYTFaXGRzL0kpykzroaquCrD5+lZNafTvZlnNqZHt5pb0M08qVBZnsnA==", + "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==", "dev": true, - "requires": { - "@jest/transform": "^27.4.5", - "@jest/types": "^27.4.2", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.0.0", - "babel-preset-jest": "^27.4.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "slash": "^3.0.0" - }, + "license": "MIT", "dependencies": { - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - } - } - }, - "babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "dependencies": { - "istanbul-lib-instrument": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz", - "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==", - "dev": true, - "requires": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "babel-plugin-jest-hoist": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.4.0.tgz", - "integrity": "sha512-Jcu7qS4OX5kTWBc45Hz7BMmgXuJqRnhatqpUhnzGC3OBYpOmf2tv6jFNwZpwM7wU7MUuv2r9IPS/ZlYOuburVw==", - "dev": true, - "requires": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.0.0", - "@types/babel__traverse": "^7.0.6" + "node_modules/avvio": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/avvio/-/avvio-8.4.0.tgz", + "integrity": "sha512-CDSwaxINFy59iNwhYnkvALBwZiTydGkOecZyPkqBpABYR1KqGEsET0VOOYDwtleZSUIdeY36DC2bSZ24CO1igA==", + "license": "MIT", + "dependencies": { + "@fastify/error": "^3.3.0", + "fastq": "^1.17.1" } }, - "babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "requires": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - } - }, - "babel-preset-jest": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.4.0.tgz", - "integrity": "sha512-NK4jGYpnBvNxcGo7/ZpZJr51jCGT+3bwwpVIDY2oNfTxJJldRtB4VAcYdgp1loDE50ODuTu+yBjpMAswv5tlpg==", - "dev": true, - "requires": { - "babel-plugin-jest-hoist": "^27.4.0", - "babel-preset-current-node-syntax": "^1.0.0" - } - }, - "balanced-match": { + "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" }, - "base64-js": { + "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "big-integer": { - "version": "1.6.51", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", - "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==" + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true + "node_modules/big-integer": { + "version": "1.6.52", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", + "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", + "license": "Unlicense", + "engines": { + "node": ">=0.6" + } }, - "bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, - "requires": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "brace-expansion": { + "node_modules/bintrees": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.2.tgz", + "integrity": "sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw==", + "license": "MIT" + }, + "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { + "license": "MIT", + "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true - }, - "browserslist": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz", - "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001286", - "electron-to-chromium": "^1.4.17", - "escalade": "^3.1.1", - "node-releases": "^2.0.1", - "picocolors": "^1.0.0" - } - }, - "bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, - "requires": { - "fast-json-stable-stringify": "2.x" + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" } }, - "bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", "dev": true, - "requires": { - "node-int64": "^0.4.0" + "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": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" } }, - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", "dev": true, - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "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==", - "dev": true - }, - "buffer-writer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", - "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" - }, - "cacache": { + "node_modules/cacache": { "version": "15.3.0", "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", - "requires": { + "license": "ISC", + "dependencies": { "@npmcli/fs": "^1.0.0", "@npmcli/move-file": "^1.0.1", "chownr": "^2.0.0", @@ -1530,1092 +2683,1252 @@ "tar": "^6.0.2", "unique-filename": "^1.1.1" }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/cacache/node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "license": "MIT", "dependencies": { - "p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "requires": { - "aggregate-error": "^3.0.0" - } - } + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cacache/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "call-bind": { + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "dev": true, - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" } }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "camelcase-keys": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-7.0.2.tgz", - "integrity": "sha512-Rjs1H+A9R+Ig+4E/9oyB66UC5Mj9Xq3N//vcLf2WzgdTi/3gUu3Z9KoqmlrEG4VuuLK8wJHofxzdQXz/knhiYg==", - "dev": true, - "requires": { - "camelcase": "^6.3.0", - "map-obj": "^4.1.0", - "quick-lru": "^5.1.1", - "type-fest": "^1.2.1" - }, - "dependencies": { - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - }, - "type-fest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", - "dev": true - } + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "caniuse-lite": { - "version": "1.0.30001286", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001286.tgz", - "integrity": "sha512-zaEMRH6xg8ESMi2eQ3R4eZ5qw/hJiVsO/HlLwniIwErij0JDr9P+8V4dtx1l+kLq6j3yy8l8W4fst1lBnat5wQ==", - "dev": true + "node_modules/chai": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.0.tgz", + "integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=12" + } }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" } }, - "char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true + "node_modules/chalk/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/check-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } }, - "chokidar": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", - "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", - "fsevents": "~2.3.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" } }, - "chownr": { + "node_modules/chownr": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" - }, - "ci-info": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", - "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==", - "dev": true + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "license": "ISC", + "engines": { + "node": ">=10" + } }, - "cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true + "node_modules/cjs-module-lexer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", + "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", + "license": "MIT" }, - "clean-stack": { + "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==" - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "license": "MIT", + "engines": { + "node": ">=6" } }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true - }, - "collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true + "node_modules/close-with-grace": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/close-with-grace/-/close-with-grace-2.2.0.tgz", + "integrity": "sha512-OdcFxnxTm/AMLPHA4Aq3J1BLpkojXP7I4G5QBQLN5TT55ED/rk04rAoDbtfNnfZ988kGXPxh1bdRLeIU9bz/lA==", + "license": "MIT" }, - "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==", + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, - "requires": { - "color-name": "~1.1.4" + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" } }, - "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==", - "dev": true + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" }, - "color-support": { + "node_modules/color-support": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==" - }, - "colorette": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", - "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", - "dev": true + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "license": "ISC", + "bin": { + "color-support": "bin.js" + } }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", "dev": true, - "requires": { - "delayed-stream": "~1.0.0" - } + "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" }, - "concat-map": { + "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" }, - "console-control-strings": { + "node_modules/console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "license": "ISC" }, - "content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dev": true, - "requires": { - "safe-buffer": "5.2.1" + "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" } }, - "convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "node_modules/cp-file": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-10.0.0.tgz", + "integrity": "sha512-vy2Vi1r2epK5WqxOLnskeKeZkdZvTKfFZQCplE3XWsP+SUJyd5XAUFC9lFgTjjXJF2GMne/UML14iEmkAaDfFg==", "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - }, + "license": "MIT", "dependencies": { - "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==", - "dev": true - } - } - }, - "cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "cp-file": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-9.1.0.tgz", - "integrity": "sha512-3scnzFj/94eb7y4wyXRWwvzLFaQp87yyfTnChIjlfYrVqp5lVO3E2hIJMeQIltUT0K2ZAB3An1qXcBmwGyvuwA==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "nested-error-stacks": "^2.0.0", - "p-event": "^4.1.0" + "graceful-fs": "^4.2.10", + "nested-error-stacks": "^2.1.1", + "p-event": "^5.0.1" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "cpy": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/cpy/-/cpy-9.0.1.tgz", - "integrity": "sha512-D9U0DR5FjTCN3oMTcFGktanHnAG5l020yvOCR1zKILmAyPP7I/9pl6NFgRbDcmSENtbK1sQLBz1p9HIOlroiNg==", + "node_modules/cpy": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/cpy/-/cpy-10.1.0.tgz", + "integrity": "sha512-VC2Gs20JcTyeQob6UViBLnyP0bYHkBh6EiKzot9vi2DmeGlFT9Wd7VG3NBrkNx/jYvFBeyDOMMHdHQhbtKLgHQ==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "arrify": "^3.0.0", - "cp-file": "^9.1.0", - "globby": "^13.1.1", - "junk": "^4.0.0", - "micromatch": "^4.0.4", - "nested-error-stacks": "^2.1.0", + "cp-file": "^10.0.0", + "globby": "^13.1.4", + "junk": "^4.0.1", + "micromatch": "^4.0.5", + "nested-error-stacks": "^2.1.1", "p-filter": "^3.0.0", - "p-map": "^5.3.0" + "p-map": "^6.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "cpy-cli": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cpy-cli/-/cpy-cli-4.1.0.tgz", - "integrity": "sha512-JA6bth6/mxPCa19SrWkIuPEBrea8vO9g1v0qhmCLnAKOfTcsNk5/X3W1o9aZuOHgugRcxdyR67rO4Gw/DA+4Qg==", + "node_modules/cpy-cli": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cpy-cli/-/cpy-cli-5.0.0.tgz", + "integrity": "sha512-fb+DZYbL9KHc0BC4NYqGRrDIJZPXUmjjtqdw4XRRg8iV8dIfghUX/WiL+q4/B/KFTy3sK6jsbUhBaz0/Hxg7IQ==", "dev": true, - "requires": { - "cpy": "^9.0.0", - "meow": "^10.1.2" + "license": "MIT", + "dependencies": { + "cpy": "^10.1.0", + "meow": "^12.0.1" + }, + "bin": { + "cpy": "cli.js" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "create-require": { + "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true + "dev": true, + "license": "MIT" }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "node_modules/cross-spawn": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "license": "MIT", + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" } }, - "crypto-js": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz", - "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==", - "dev": true + "node_modules/cross-spawn/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } }, - "cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", - "dev": true + "node_modules/crypto-js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==", + "license": "MIT" }, - "cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "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==", "dev": true, - "requires": { - "cssom": "~0.3.6" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "license": "MIT", "dependencies": { - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - } + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" } }, - "data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "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==", "dev": true, - "requires": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "dateformat": { + "node_modules/dateformat": { "version": "4.6.3", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", - "dev": true - }, - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "requires": { - "ms": "2.1.2" + "dev": true, + "license": "MIT", + "engines": { + "node": "*" } }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, - "decamelize-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", - "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", - "dev": true, - "requires": { - "decamelize": "^1.1.0", - "map-obj": "^1.0.0" - }, + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", "dependencies": { - "map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", - "dev": true + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true } } }, - "decimal.js": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", - "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", - "dev": true - }, - "decompress-response": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", - "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", "dev": true, - "requires": { - "mimic-response": "^2.0.0" + "license": "MIT", + "engines": { + "node": ">=6" } }, - "dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", - "dev": true - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true - }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "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==", "dev": true, - "requires": { - "object-keys": "^1.0.12" + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "delegates": { + "node_modules/delegates": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" - }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" - }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", - "dev": true - }, - "detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "license": "MIT" }, - "detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } }, - "diff": { + "node_modules/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - }, - "diff-sequences": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.4.0.tgz", - "integrity": "sha512-YqiQzkrsmHMH5uuh8OdQFU9/ZpADnwzml8z0O5HvRNda+5UZsaX/xN+AAxfR2hWq1Y7HZnAzO9J5lJXOuDz2Ww==", - "dev": true + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } }, - "dir-glob": { + "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "path-type": "^4.0.0" }, - "dependencies": { - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - } + "engines": { + "node": ">=8" } }, - "domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", - "dev": true, - "requires": { - "webidl-conversions": "^5.0.0" - }, - "dependencies": { - "webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "dev": true - } - } + "node_modules/discontinuous-range": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz", + "integrity": "sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ==", + "license": "MIT" }, - "dotty": { + "node_modules/dotty": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/dotty/-/dotty-0.1.2.tgz", - "integrity": "sha512-V0EWmKeH3DEhMwAZ+8ZB2Ao4OK6p++Z0hsDtZq3N0+0ZMVqkzrcEGROvOnZpLnvBg5PTNG23JEDLAm64gPaotQ==" - }, - "duplexify": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", - "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", - "requires": { - "end-of-stream": "^1.4.1", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1", - "stream-shift": "^1.0.0" - } + "integrity": "sha512-V0EWmKeH3DEhMwAZ+8ZB2Ao4OK6p++Z0hsDtZq3N0+0ZMVqkzrcEGROvOnZpLnvBg5PTNG23JEDLAm64gPaotQ==", + "license": "BSD-3-Clause" }, - "dynamic-dedupe": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz", - "integrity": "sha1-BuRMIj9eTpTXjvnbI6ZRXOL5YqE=", + "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==", "dev": true, - "requires": { - "xtend": "^4.0.0" + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" } }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", - "dev": true - }, - "electron-to-chromium": { - "version": "1.4.18", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.18.tgz", - "integrity": "sha512-i7nKjGGBE1+YUIbfLObA1EZPmN7J1ITEllbhusDk+KIk6V6gUxN9PFe36v+Sd+8Cg0k3cgUv9lQhQZalr8rggw==", - "dev": true - }, - "emittery": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", - "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", - "dev": true + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" }, - "emoji-regex": { + "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==" - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", - "dev": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" }, - "encoding": { + "node_modules/encoding": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "license": "MIT", "optional": true, - "requires": { + "dependencies": { "iconv-lite": "^0.6.2" } }, - "encoding-negotiator": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/encoding-negotiator/-/encoding-negotiator-2.0.1.tgz", - "integrity": "sha512-GSK7qphNR4iPcejfAlZxKDoz3xMhnspwImK+Af5WhePS9jUpK/Oh7rUdyENWu+9rgDflOCTmAojBsgsvM8neAQ==", - "dev": true - }, - "end-of-stream": { + "node_modules/end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "requires": { + "dev": true, + "license": "MIT", + "dependencies": { "once": "^1.4.0" } }, - "env-paths": { + "node_modules/env-paths": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==" + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "license": "MIT", + "engines": { + "node": ">=6" + } }, - "err-code": { + "node_modules/err-code": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==" + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "license": "MIT" }, - "error-ex": { + "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "is-arrayish": "^0.2.1" } }, - "es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", - "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", + "node_modules/es-abstract": { + "version": "1.23.9", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.9.tgz", + "integrity": "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.0", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-regex": "^1.2.1", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.0", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.3", "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.3", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.18" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "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==", "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" + "license": "MIT", + "engines": { + "node": ">= 0.4" } }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", - "dev": true + "node_modules/es-module-lexer": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz", + "integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==", + "dev": true, + "license": "MIT" }, - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } }, - "escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "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==", "dev": true, - "requires": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" } }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true + "node_modules/esbuild": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz", + "integrity": "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.1", + "@esbuild/android-arm": "0.25.1", + "@esbuild/android-arm64": "0.25.1", + "@esbuild/android-x64": "0.25.1", + "@esbuild/darwin-arm64": "0.25.1", + "@esbuild/darwin-x64": "0.25.1", + "@esbuild/freebsd-arm64": "0.25.1", + "@esbuild/freebsd-x64": "0.25.1", + "@esbuild/linux-arm": "0.25.1", + "@esbuild/linux-arm64": "0.25.1", + "@esbuild/linux-ia32": "0.25.1", + "@esbuild/linux-loong64": "0.25.1", + "@esbuild/linux-mips64el": "0.25.1", + "@esbuild/linux-ppc64": "0.25.1", + "@esbuild/linux-riscv64": "0.25.1", + "@esbuild/linux-s390x": "0.25.1", + "@esbuild/linux-x64": "0.25.1", + "@esbuild/netbsd-arm64": "0.25.1", + "@esbuild/netbsd-x64": "0.25.1", + "@esbuild/openbsd-arm64": "0.25.1", + "@esbuild/openbsd-x64": "0.25.1", + "@esbuild/sunos-x64": "0.25.1", + "@esbuild/win32-arm64": "0.25.1", + "@esbuild/win32-ia32": "0.25.1", + "@esbuild/win32-x64": "0.25.1" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", - "dev": true + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } }, - "events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" - }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } }, - "expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "dev": true - }, - "expect": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.4.2.tgz", - "integrity": "sha512-BjAXIDC6ZOW+WBFNg96J22D27Nq5ohn+oGcuP2rtOtcjuxNoV9McpQ60PcQWhdFOSBIQdR72e+4HdnbZTFSTyg==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "ansi-styles": "^5.0.0", - "jest-get-type": "^27.4.0", - "jest-matcher-utils": "^27.4.2", - "jest-message-util": "^27.4.2", - "jest-regex-util": "^27.4.0" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } + "node_modules/expect-type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.0.tgz", + "integrity": "sha512-80F22aiJ3GLyVnS/B3HzgR6RelZVumzj9jkL0Rhz4h0xYbNW9PjlQz5h3J/SShErbXBc295vseR4/MIbVmUbeA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" } }, - "fast-decode-uri-component": { + "node_modules/fast-content-type-parse": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-1.1.0.tgz", + "integrity": "sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ==", + "license": "MIT" + }, + "node_modules/fast-copy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-3.0.2.tgz", + "integrity": "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-decode-uri-component": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz", "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==", - "dev": true + "license": "MIT" }, - "fast-deep-equal": { + "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==", - "dev": true + "license": "MIT" }, - "fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" } }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "node_modules/fast-json-stringify": { + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-5.16.1.tgz", + "integrity": "sha512-KAdnLvy1yu/XrRtP+LJnxbBGrhN+xXu+gt3EUvZhYGKCr3lFHq/7UFJHHFgmJKoqlh6B40bZLEv7w46B0mqn1g==", + "license": "MIT", + "dependencies": { + "@fastify/merge-json-schemas": "^0.1.0", + "ajv": "^8.10.0", + "ajv-formats": "^3.0.1", + "fast-deep-equal": "^3.1.3", + "fast-uri": "^2.1.0", + "json-schema-ref-resolver": "^1.0.1", + "rfdc": "^1.2.0" + } }, - "fast-json-stringify": { - "version": "2.7.12", - "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-2.7.12.tgz", - "integrity": "sha512-4hjwZDPmgj/ZUKXhEWovGPciE/5mWtAIQQxN+2VBDFun7DRTk2oOItbu9ZZp6kqj+eZ/u7z+dgBgM74cfGRnBQ==", - "dev": true, - "requires": { - "ajv": "^6.11.0", - "deepmerge": "^4.2.2", - "rfdc": "^1.2.0", - "string-similarity": "^4.0.1" + "node_modules/fast-json-stringify/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" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } } }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true + "node_modules/fast-querystring": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.1.2.tgz", + "integrity": "sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==", + "license": "MIT", + "dependencies": { + "fast-decode-uri-component": "^1.0.1" + } }, - "fast-redact": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.0.2.tgz", - "integrity": "sha512-YN+CYfCVRVMUZOUPeinHNKgytM1wPI/C/UCLEi56EsY2dwwvI00kIJHJoI7pMVqGoMew8SMZ2SSfHKHULHXDsg==" + "node_modules/fast-redact": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz", + "integrity": "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==", + "license": "MIT", + "engines": { + "node": ">=6" + } }, - "fast-safe-stringify": { + "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==", - "dev": true - }, - "fastify": { - "version": "3.27.4", - "resolved": "https://registry.npmjs.org/fastify/-/fastify-3.27.4.tgz", - "integrity": "sha512-SOfnHBxG9zxCSIvt6aHoR/cao8QBddWmGP/mb5KQKRc+KI1kB7b79M2hCDOTSyHdLAF2OX+oI6X3weeLc+MqKg==", - "dev": true, - "requires": { - "@fastify/ajv-compiler": "^1.0.0", - "abstract-logging": "^2.0.0", - "avvio": "^7.1.2", - "fast-json-stringify": "^2.5.2", - "fastify-error": "^0.3.0", - "find-my-way": "^4.5.0", - "flatstr": "^1.0.12", - "light-my-request": "^4.2.0", - "pino": "^6.13.0", - "process-warning": "^1.0.0", - "proxy-addr": "^2.0.7", - "rfdc": "^1.1.4", - "secure-json-parse": "^2.0.0", - "semver": "^7.3.2", - "tiny-lru": "^8.0.1" - }, - "dependencies": { - "pino": { - "version": "6.13.4", - "resolved": "https://registry.npmjs.org/pino/-/pino-6.13.4.tgz", - "integrity": "sha512-g4tHSISmQJYUEKEMVdaZ+ZokWwFnTwZL5JPn+lnBVZ1BuBbrSchrXwQINknkM5+Q4fF6U9NjiI8PWwwMDHt9zA==", - "dev": true, - "requires": { - "fast-redact": "^3.0.0", - "fast-safe-stringify": "^2.0.8", - "flatstr": "^1.0.12", - "pino-std-serializers": "^3.1.0", - "process-warning": "^1.0.0", - "quick-format-unescaped": "^4.0.3", - "sonic-boom": "^1.0.2" - } - }, - "pino-std-serializers": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-3.2.0.tgz", - "integrity": "sha512-EqX4pwDPrt3MuOAAUBMU0Tk5kR/YcCM5fNPEzgCO2zJ5HfX0vbiH9HbJglnyeQsN96Kznae6MWD47pZB5avTrg==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-2.4.0.tgz", + "integrity": "sha512-ypuAmmMKInk5q7XcepxlnUWDLWv4GFtaJqAzWKqn62IpQ3pejtr5dTVbt3vwqVaMKmkNR55sTT+CqUKIaT21BA==", + "license": "MIT" + }, + "node_modules/fastify": { + "version": "4.29.0", + "resolved": "https://registry.npmjs.org/fastify/-/fastify-4.29.0.tgz", + "integrity": "sha512-MaaUHUGcCgC8fXQDsDtioaCcag1fmPJ9j64vAKunqZF4aSub040ZGi/ag8NGE2714yREPOKZuHCfpPzuUD3UQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" }, - "sonic-boom": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-1.4.1.tgz", - "integrity": "sha512-LRHh/A8tpW7ru89lrlkU4AszXt1dbwSjVWguGrmlxE7tawVmDBlI1PILMkXAxJTwqhgsEeTHzj36D5CmHgQmNg==", - "dev": true, - "requires": { - "atomic-sleep": "^1.0.0", - "flatstr": "^1.0.12" - } + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" } + ], + "license": "MIT", + "dependencies": { + "@fastify/ajv-compiler": "^3.5.0", + "@fastify/error": "^3.4.0", + "@fastify/fast-json-stringify-compiler": "^4.3.0", + "abstract-logging": "^2.0.1", + "avvio": "^8.3.0", + "fast-content-type-parse": "^1.1.0", + "fast-json-stringify": "^5.8.0", + "find-my-way": "^8.0.0", + "light-my-request": "^5.11.0", + "pino": "^9.0.0", + "process-warning": "^3.0.0", + "proxy-addr": "^2.0.7", + "rfdc": "^1.3.0", + "secure-json-parse": "^2.7.0", + "semver": "^7.5.4", + "toad-cache": "^3.3.0" } }, - "fastify-cors": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/fastify-cors/-/fastify-cors-6.0.3.tgz", - "integrity": "sha512-fMbXubKKyBHHCfSBtsCi3+7VyVRdhJQmGes5gM+eGKkRErCdm0NaYO0ozd31BQBL1ycoTIjbqOZhJo4RTF/Vlg==", - "dev": true, - "requires": { - "fastify-plugin": "^3.0.0", - "vary": "^1.1.2" + "node_modules/fastify-metrics": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/fastify-metrics/-/fastify-metrics-10.6.0.tgz", + "integrity": "sha512-QIPncCnwBOEObMn+VaRhsBC1ox8qEsaiYF2sV/A1UbXj7ic70W8/HNn/hlEC2W8JQbBeZMx++o1um2fPfhsFDQ==", + "license": "MIT", + "dependencies": { + "fastify-plugin": "^4.3.0", + "prom-client": "^14.2.0" + }, + "peerDependencies": { + "fastify": ">=4" } }, - "fastify-error": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/fastify-error/-/fastify-error-0.3.1.tgz", - "integrity": "sha512-oCfpcsDndgnDVgiI7bwFKAun2dO+4h84vBlkWsWnz/OUK9Reff5UFoFl241xTiLeHWX/vU9zkDVXqYUxjOwHcQ==", - "dev": true + "node_modules/fastify-plugin": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-4.5.1.tgz", + "integrity": "sha512-stRHYGeuqpEZTL1Ef0Ovr2ltazUT9g844X5z/zEBFLG8RYlpDiOCIG+ATvYEp+/zmc7sN29mcIMp8gvYplYPIQ==", + "license": "MIT" }, - "fastify-plugin": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-3.0.0.tgz", - "integrity": "sha512-ZdCvKEEd92DNLps5n0v231Bha8bkz1DjnPP/aEz37rz/q42Z5JVLmgnqR4DYuNn3NXAO3IDCPyRvgvxtJ4Ym4w==", - "dev": true - }, - "fastify-static": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/fastify-static/-/fastify-static-4.5.0.tgz", - "integrity": "sha512-Q7Tgl55AjsmBwiO4hKYib2BUCt+XTWLJ6Xp8YPPHU3EsrKNpevJ4cz8pjf1Ey1QhHw9O8Y2FDKdu+IC74oHvqw==", - "dev": true, - "requires": { - "content-disposition": "^0.5.3", - "encoding-negotiator": "^2.0.1", - "fastify-plugin": "^3.0.0", - "glob": "^7.1.4", - "p-limit": "^3.1.0", - "readable-stream": "^3.4.0", - "send": "^0.17.1" + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" } }, - "fastify-swagger": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/fastify-swagger/-/fastify-swagger-5.0.0.tgz", - "integrity": "sha512-JdOn5CNKLhVPHDHTEpkmUaWNN/Y51R97TlSOICWT1WB41ZO6oiq9eUZIg0fLJABU6QsrcsiUxUkBBuuEL/g8Vw==", + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, - "requires": { - "fastify-plugin": "^3.0.0", - "fastify-static": "^4.0.0", - "js-yaml": "^4.0.0", - "json-schema-resolver": "^1.3.0", - "openapi-types": "^10.0.0" + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, - "fastify-warning": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/fastify-warning/-/fastify-warning-0.2.0.tgz", - "integrity": "sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw==", - "dev": true + "node_modules/find-my-way": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-8.2.2.tgz", + "integrity": "sha512-Dobi7gcTEq8yszimcfp/R7+owiT4WncAJ7VTTgFH1jYJ5GaG1FbhjwDG820hptN0QDFvzVY3RfCzdInvGPGzjA==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-querystring": "^1.0.0", + "safe-regex2": "^3.1.0" + }, + "engines": { + "node": ">=14" + } }, - "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", "dev": true, - "requires": { - "reusify": "^1.0.4" + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "fb-watchman": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", "dev": true, - "requires": { - "bser": "2.1.1" + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "node_modules/foreground-child/node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, - "requires": { - "to-regex-range": "^5.0.1" + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" } }, - "find-my-way": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-4.5.1.tgz", - "integrity": "sha512-kE0u7sGoUFbMXcOG/xpkmz4sRLCklERnBcg7Ftuu1iAxsfEt2S46RLJ3Sq7vshsEy2wJT2hZxE58XZK27qa8kg==", + "node_modules/foreground-child/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, - "requires": { - "fast-decode-uri-component": "^1.0.1", - "fast-deep-equal": "^3.1.3", - "safe-regex2": "^2.0.0", - "semver-store": "^0.3.0" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "node_modules/foreground-child/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "flatstr": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/flatstr/-/flatstr-1.0.12.tgz", - "integrity": "sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw==", - "dev": true + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, - "form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "node_modules/foreground-child/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" } }, - "forwarded": { + "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "dev": true - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", - "dev": true - }, - "from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "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" - } - }, - "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==", - "dev": true - }, - "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==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } + "license": "MIT", + "engines": { + "node": ">= 0.6" } }, - "fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true - }, - "fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "requires": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "dependencies": { - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true - } - } + "node_modules/forwarded-parse": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/forwarded-parse/-/forwarded-parse-2.1.2.tgz", + "integrity": "sha512-alTFZZQDKMporBH77856pXgzhEzaUVmLCDk+egLgIgHst3Tpndzz8MnKe+GzRJRfvVdn69HhpW7cmXzvtLvJAw==", + "license": "MIT" }, - "fs-minipass": { + "node_modules/fs-minipass": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "requires": { + "license": "ISC", + "dependencies": { "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" } }, - "fs.realpath": { + "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, - "optional": true + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "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" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "gauge": { + "node_modules/gauge": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", - "requires": { + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.2", "console-control-strings": "^1.0.0", @@ -2625,1372 +3938,1154 @@ "string-width": "^4.2.3", "strip-ansi": "^6.0.1", "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" } }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "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==", "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true + "node_modules/get-stdin": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", + "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "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==", "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=", - "dev": true - }, - "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "requires": { + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", + "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "glob-parent": { + "node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, - "requires": { + "license": "ISC", + "dependencies": { "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" } }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "globby": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.1.tgz", - "integrity": "sha512-XMzoDZbGZ37tufiv7g0N4F/zp3zkwdFtVbV3EHsVl1KQr4RPLfNoT068/97RPshz2J5xYNEjLKKBKaGHifBd3Q==", + "node_modules/globby": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", + "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "dir-glob": "^3.0.1", - "fast-glob": "^3.2.11", - "ignore": "^5.2.0", + "fast-glob": "^3.3.0", + "ignore": "^5.2.4", "merge2": "^1.4.1", "slash": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "hard-rejection": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", - "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", - "dev": true + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "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==", "dev": true, - "requires": { - "function-bind": "^1.1.1" + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", - "dev": true - }, - "has-flag": { + "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "has-symbols": { + "node_modules/has-property-descriptors": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", "dev": true, - "requires": { - "has-symbols": "^1.0.2" + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "has-unicode": { + "node_modules/has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "license": "ISC" + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } }, - "hosted-git-info": { + "node_modules/help-me": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", + "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==", + "dev": true, + "license": "MIT" + }, + "node_modules/hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", "dev": true, - "requires": { - "whatwg-encoding": "^1.0.5" - } + "license": "ISC" }, - "html-escaper": { + "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" - }, - "http-errors": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", "dev": true, - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.1" - } + "license": "MIT" + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "license": "BSD-2-Clause" }, - "http-proxy-agent": { + "node_modules/http-proxy-agent": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "requires": { + "license": "MIT", + "dependencies": { "@tootallnate/once": "1", "agent-base": "6", "debug": "4" + }, + "engines": { + "node": ">= 6" } }, - "https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "requires": { + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "dependencies": { "agent-base": "6", "debug": "4" + }, + "engines": { + "node": ">= 6" } }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true - }, - "humanize-ms": { + "node_modules/humanize-ms": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", - "requires": { + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "license": "MIT", + "dependencies": { "ms": "^2.0.0" } }, - "iconv-lite": { + "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", "optional": true, - "requires": { + "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "ieee754": { + "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" }, - "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } }, - "import-local": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.3.tgz", - "integrity": "sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA==", + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", "dev": true, - "requires": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" + "license": "ISC" + }, + "node_modules/import-in-the-middle": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-1.13.1.tgz", + "integrity": "sha512-k2V9wNm9B+ysuelDTHjI9d5KPc4l8zAZTGqj+pcynvWkypZd857ryzN8jNC7Pg2YZXNMJcHRPpaDyCBbNyVRpA==", + "license": "Apache-2.0", + "dependencies": { + "acorn": "^8.14.0", + "acorn-import-attributes": "^1.9.5", + "cjs-module-lexer": "^1.2.2", + "module-details-from-path": "^1.0.3" } }, - "imurmurhash": { + "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } }, - "indent-string": { + "node_modules/indent-string": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "infer-owner": { + "node_modules/infer-owner": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==" + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "license": "ISC" }, - "inflight": { + "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", + "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, - "inherits": { + "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" }, - "internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "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==", "dev": true, - "requires": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" } }, - "into-stream": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-6.0.0.tgz", - "integrity": "sha512-XHbaOAvP+uFKUFsOgoNPRjLkwB+I22JFPFe5OjTkQ0nwgj6+pSjb4NmB6VMxaPshLiOf+zcpOCBQuLwC1KHhZA==", - "dev": true, - "requires": { - "from2": "^2.3.0", - "p-is-promise": "^3.0.0" + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "license": "MIT", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" } }, - "ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" - }, - "ipaddr.js": { + "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==", - "dev": true + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "is-arrayish": { + "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" }, - "is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", "dev": true, - "requires": { - "has-bigints": "^1.0.1" + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-binary-path": { + "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" } }, - "is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "dev": true - }, - "is-core-module": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", - "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", + "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==", "dev": true, - "requires": { - "has": "^1.0.3" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "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==", "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "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==" - }, - "is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-lambda": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU=" - }, - "is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", + "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==", "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-plain-obj": { + "node_modules/is-date-object": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", - "dev": true - }, - "is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", - "dev": true - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, - "is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "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==", "dev": true, - "requires": { - "has-symbols": "^1.0.2" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true + "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" + } }, - "is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "node_modules/is-generator-function": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", + "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", "dev": true, - "requires": { - "call-bind": "^1.0.2" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-proto": "^1.0.0", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, - "istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true - }, - "istanbul-lib-instrument": { + "node_modules/is-glob": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, - "requires": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" - }, + "license": "MIT", "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - } + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "license": "MIT" }, - "istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "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==", "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "istanbul-reports": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.1.tgz", - "integrity": "sha512-q1kvhAXWSsXfMjCdNHNPKZZv94OlspKnoGv+R9RGbnqOOQ0VbNfLFgQDVgi7hHenKsndGq3/o0OBdzDXthWcNw==", + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" + "license": "MIT", + "engines": { + "node": ">=0.12.0" } }, - "jest": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest/-/jest-27.4.5.tgz", - "integrity": "sha512-uT5MiVN3Jppt314kidCk47MYIRilJjA/l2mxwiuzzxGUeJIvA8/pDaJOAX5KWvjAo7SCydcW0/4WEtgbLMiJkg==", + "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==", "dev": true, - "requires": { - "@jest/core": "^27.4.5", - "import-local": "^3.0.2", - "jest-cli": "^27.4.5" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "jest-changed-files": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.4.2.tgz", - "integrity": "sha512-/9x8MjekuzUQoPjDHbBiXbNEBauhrPU2ct7m8TfCg69ywt1y/N+yYwGh3gCpnqUS3klYWDU/lSNgv+JhoD2k1A==", + "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==", "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "execa": "^5.0.0", - "throat": "^6.0.1" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "jest-circus": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.4.5.tgz", - "integrity": "sha512-eTNWa9wsvBwPykhMMShheafbwyakcdHZaEYh5iRrQ0PFJxkDP/e3U/FvzGuKWu2WpwUA3C3hPlfpuzvOdTVqnw==", + "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==", "dev": true, - "requires": { - "@jest/environment": "^27.4.4", - "@jest/test-result": "^27.4.2", - "@jest/types": "^27.4.2", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "expect": "^27.4.2", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.4.2", - "jest-matcher-utils": "^27.4.2", - "jest-message-util": "^27.4.2", - "jest-runtime": "^27.4.5", - "jest-snapshot": "^27.4.5", - "jest-util": "^27.4.2", - "pretty-format": "^27.4.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.3", - "throat": "^6.0.1" - }, - "dependencies": { - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - } + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "jest-cli": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.4.5.tgz", - "integrity": "sha512-hrky3DSgE0u7sQxaCL7bdebEPHx5QzYmrGuUjaPLmPE8jx5adtvGuOlRspvMoVLTTDOHRnZDoRLYJuA+VCI7Hg==", - "dev": true, - "requires": { - "@jest/core": "^27.4.5", - "@jest/test-result": "^27.4.2", - "@jest/types": "^27.4.2", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "import-local": "^3.0.2", - "jest-config": "^27.4.5", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.2", - "prompts": "^2.0.1", - "yargs": "^16.2.0" - } - }, - "jest-config": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.4.5.tgz", - "integrity": "sha512-t+STVJtPt+fpqQ8GBw850NtSQbnDOw/UzdPfzDaHQ48/AylQlW7LHj3dH+ndxhC1UxJ0Q3qkq7IH+nM1skwTwA==", - "dev": true, - "requires": { - "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^27.4.5", - "@jest/types": "^27.4.2", - "babel-jest": "^27.4.5", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.1", - "graceful-fs": "^4.2.4", - "jest-circus": "^27.4.5", - "jest-environment-jsdom": "^27.4.4", - "jest-environment-node": "^27.4.4", - "jest-get-type": "^27.4.0", - "jest-jasmine2": "^27.4.5", - "jest-regex-util": "^27.4.0", - "jest-resolve": "^27.4.5", - "jest-runner": "^27.4.5", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.2", - "micromatch": "^4.0.4", - "pretty-format": "^27.4.2", - "slash": "^3.0.0" - }, - "dependencies": { - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - } + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "jest-diff": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.4.2.tgz", - "integrity": "sha512-ujc9ToyUZDh9KcqvQDkk/gkbf6zSaeEg9AiBxtttXW59H/AcqEYp1ciXAtJp+jXWva5nAf/ePtSsgWwE5mqp4Q==", + "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==", "dev": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^27.4.0", - "jest-get-type": "^27.4.0", - "pretty-format": "^27.4.2" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "jest-docblock": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.4.0.tgz", - "integrity": "sha512-7TBazUdCKGV7svZ+gh7C8esAnweJoG+SvcF6Cjqj4l17zA2q1cMwx2JObSioubk317H+cjcHgP+7fTs60paulg==", + "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==", "dev": true, - "requires": { - "detect-newline": "^3.0.0" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "jest-each": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.4.2.tgz", - "integrity": "sha512-53V2MNyW28CTruB3lXaHNk6PkiIFuzdOC9gR3C6j8YE/ACfrPnz+slB0s17AgU1TtxNzLuHyvNlLJ+8QYw9nBg==", + "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==", "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "chalk": "^4.0.0", - "jest-get-type": "^27.4.0", - "jest-util": "^27.4.2", - "pretty-format": "^27.4.2" + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "jest-environment-jsdom": { - "version": "27.4.4", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.4.4.tgz", - "integrity": "sha512-cYR3ndNfHBqQgFvS1RL7dNqSvD//K56j/q1s2ygNHcfTCAp12zfIromO1w3COmXrxS8hWAh7+CmZmGCIoqGcGA==", + "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==", "dev": true, - "requires": { - "@jest/environment": "^27.4.4", - "@jest/fake-timers": "^27.4.2", - "@jest/types": "^27.4.2", - "@types/node": "*", - "jest-mock": "^27.4.2", - "jest-util": "^27.4.2", - "jsdom": "^16.6.0" + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "jest-environment-node": { - "version": "27.4.4", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.4.4.tgz", - "integrity": "sha512-D+v3lbJ2GjQTQR23TK0kY3vFVmSeea05giInI41HHOaJnAwOnmUHTZgUaZL+VxUB43pIzoa7PMwWtCVlIUoVoA==", + "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==", "dev": true, - "requires": { - "@jest/environment": "^27.4.4", - "@jest/fake-timers": "^27.4.2", - "@jest/types": "^27.4.2", - "@types/node": "*", - "jest-mock": "^27.4.2", - "jest-util": "^27.4.2" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "jest-get-type": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz", - "integrity": "sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==", - "dev": true - }, - "jest-haste-map": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.4.5.tgz", - "integrity": "sha512-oJm1b5qhhPs78K24EDGifWS0dELYxnoBiDhatT/FThgB9yxqUm5F6li3Pv+Q+apMBmmPNzOBnZ7ZxWMB1Leq1Q==", + "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==", "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "@types/graceful-fs": "^4.1.2", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.3.2", - "graceful-fs": "^4.2.4", - "jest-regex-util": "^27.4.0", - "jest-serializer": "^27.4.0", - "jest-util": "^27.4.2", - "jest-worker": "^27.4.5", - "micromatch": "^4.0.4", - "walker": "^1.0.7" - } - }, - "jest-jasmine2": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.4.5.tgz", - "integrity": "sha512-oUnvwhJDj2LhOiUB1kdnJjkx8C5PwgUZQb9urF77mELH9DGR4e2GqpWQKBOYXWs5+uTN9BGDqRz3Aeg5Wts7aw==", - "dev": true, - "requires": { - "@babel/traverse": "^7.1.0", - "@jest/environment": "^27.4.4", - "@jest/source-map": "^27.4.0", - "@jest/test-result": "^27.4.2", - "@jest/types": "^27.4.2", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "expect": "^27.4.2", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.4.2", - "jest-matcher-utils": "^27.4.2", - "jest-message-util": "^27.4.2", - "jest-runtime": "^27.4.5", - "jest-snapshot": "^27.4.5", - "jest-util": "^27.4.2", - "pretty-format": "^27.4.2", - "throat": "^6.0.1" - } - }, - "jest-leak-detector": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.4.2.tgz", - "integrity": "sha512-ml0KvFYZllzPBJWDei3mDzUhyp/M4ubKebX++fPaudpe8OsxUE+m+P6ciVLboQsrzOCWDjE20/eXew9QMx/VGw==", - "dev": true, - "requires": { - "jest-get-type": "^27.4.0", - "pretty-format": "^27.4.2" - } - }, - "jest-matcher-utils": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.4.2.tgz", - "integrity": "sha512-jyP28er3RRtMv+fmYC/PKG8wvAmfGcSNproVTW2Y0P/OY7/hWUOmsPfxN1jOhM+0u2xU984u2yEagGivz9OBGQ==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "jest-diff": "^27.4.2", - "jest-get-type": "^27.4.0", - "pretty-format": "^27.4.2" - } - }, - "jest-message-util": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.4.2.tgz", - "integrity": "sha512-OMRqRNd9E0DkBLZpFtZkAGYOXl6ZpoMtQJWTAREJKDOFa0M6ptB7L67tp+cszMBkvSgKOhNtQp2Vbcz3ZZKo/w==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.4.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.4", - "pretty-format": "^27.4.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "dependencies": { - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - } + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "jest-mock": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.4.2.tgz", - "integrity": "sha512-PDDPuyhoukk20JrQKeofK12hqtSka7mWH0QQuxSNgrdiPsrnYYLS6wbzu/HDlxZRzji5ylLRULeuI/vmZZDrYA==", + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "@types/node": "*" - } + "license": "MIT" }, - "jest-pnp-resolver": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true - }, - "jest-regex-util": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.4.0.tgz", - "integrity": "sha512-WeCpMpNnqJYMQoOjm1nTtsgbR4XHAk1u00qDoNBQoykM280+/TmgA5Qh5giC1ecy6a5d4hbSsHzpBtu5yvlbEg==", - "dev": true - }, - "jest-resolve": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.4.5.tgz", - "integrity": "sha512-xU3z1BuOz/hUhVUL+918KqUgK+skqOuUsAi7A+iwoUldK6/+PW+utK8l8cxIWT9AW7IAhGNXjSAh1UYmjULZZw==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.5", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.2", - "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", - "slash": "^3.0.0" - }, - "dependencies": { - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - } - } + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" }, - "jest-resolve-dependencies": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.4.5.tgz", - "integrity": "sha512-elEVvkvRK51y037NshtEkEnukMBWvlPzZHiL847OrIljJ8yIsujD2GXRPqDXC4rEVKbcdsy7W0FxoZb4WmEs7w==", + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "jest-regex-util": "^27.4.0", - "jest-snapshot": "^27.4.5" + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" } }, - "jest-runner": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.4.5.tgz", - "integrity": "sha512-/irauncTfmY1WkTaRQGRWcyQLzK1g98GYG/8QvIPviHgO1Fqz1JYeEIsSfF+9mc/UTA6S+IIHFgKyvUrtiBIZg==", + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, - "requires": { - "@jest/console": "^27.4.2", - "@jest/environment": "^27.4.4", - "@jest/test-result": "^27.4.2", - "@jest/transform": "^27.4.5", - "@jest/types": "^27.4.2", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.8.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-docblock": "^27.4.0", - "jest-environment-jsdom": "^27.4.4", - "jest-environment-node": "^27.4.4", - "jest-haste-map": "^27.4.5", - "jest-leak-detector": "^27.4.2", - "jest-message-util": "^27.4.2", - "jest-resolve": "^27.4.5", - "jest-runtime": "^27.4.5", - "jest-util": "^27.4.2", - "jest-worker": "^27.4.5", - "source-map-support": "^0.5.6", - "throat": "^6.0.1" - } - }, - "jest-runtime": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.4.5.tgz", - "integrity": "sha512-CIYqwuJQXHQtPd/idgrx4zgJ6iCb6uBjQq1RSAGQrw2S8XifDmoM1Ot8NRd80ooAm+ZNdHVwsktIMGlA1F1FAQ==", - "dev": true, - "requires": { - "@jest/console": "^27.4.2", - "@jest/environment": "^27.4.4", - "@jest/globals": "^27.4.4", - "@jest/source-map": "^27.4.0", - "@jest/test-result": "^27.4.2", - "@jest/transform": "^27.4.5", - "@jest/types": "^27.4.2", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "execa": "^5.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.5", - "jest-message-util": "^27.4.2", - "jest-mock": "^27.4.2", - "jest-regex-util": "^27.4.0", - "jest-resolve": "^27.4.5", - "jest-snapshot": "^27.4.5", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.2", - "slash": "^3.0.0", - "strip-bom": "^4.0.0", - "yargs": "^16.2.0" - }, - "dependencies": { - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - } + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" } }, - "jest-serializer": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.4.0.tgz", - "integrity": "sha512-RDhpcn5f1JYTX2pvJAGDcnsNTnsV9bjYPU8xcV+xPwOXnUPOQwf4ZEuiU6G9H1UztH+OapMgu/ckEVwO87PwnQ==", + "node_modules/istanbul-lib-source-maps": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", "dev": true, - "requires": { - "@types/node": "*", - "graceful-fs": "^4.2.4" - } - }, - "jest-snapshot": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.4.5.tgz", - "integrity": "sha512-eCi/iM1YJFrJWiT9de4+RpWWWBqsHiYxFG9V9o/n0WXs6GpW4lUt4FAHAgFPTLPqCUVzrMQmSmTZSgQzwqR7IQ==", - "dev": true, - "requires": { - "@babel/core": "^7.7.2", - "@babel/generator": "^7.7.2", - "@babel/parser": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.0.0", - "@jest/transform": "^27.4.5", - "@jest/types": "^27.4.2", - "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^27.4.2", - "graceful-fs": "^4.2.4", - "jest-diff": "^27.4.2", - "jest-get-type": "^27.4.0", - "jest-haste-map": "^27.4.5", - "jest-matcher-utils": "^27.4.2", - "jest-message-util": "^27.4.2", - "jest-resolve": "^27.4.5", - "jest-util": "^27.4.2", - "natural-compare": "^1.4.0", - "pretty-format": "^27.4.2", - "semver": "^7.3.2" - } - }, - "jest-util": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.4.2.tgz", - "integrity": "sha512-YuxxpXU6nlMan9qyLuxHaMMOzXAl5aGZWCSzben5DhLHemYQxCc4YK+4L3ZrCutT8GPQ+ui9k5D8rUJoDioMnA==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.4", - "picomatch": "^2.2.3" - } - }, - "jest-validate": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.4.2.tgz", - "integrity": "sha512-hWYsSUej+Fs8ZhOm5vhWzwSLmVaPAxRy+Mr+z5MzeaHm9AxUpXdoVMEW4R86y5gOobVfBsMFLk4Rb+QkiEpx1A==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^27.4.0", - "leven": "^3.1.0", - "pretty-format": "^27.4.2" - }, - "dependencies": { - "camelcase": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.1.tgz", - "integrity": "sha512-tVI4q5jjFV5CavAU8DXfza/TJcZutVKo/5Foskmsqcm0MsL91moHvwiGNnqaa2o6PF/7yT5ikDRcVcl8Rj6LCA==", - "dev": true - } + "license": "BSD-3-Clause", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" + }, + "engines": { + "node": ">=10" } }, - "jest-watcher": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.4.2.tgz", - "integrity": "sha512-NJvMVyyBeXfDezhWzUOCOYZrUmkSCiatpjpm+nFUid74OZEHk6aMLrZAukIiFDwdbqp6mTM6Ui1w4oc+8EobQg==", + "node_modules/istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", "dev": true, - "requires": { - "@jest/test-result": "^27.4.2", - "@jest/types": "^27.4.2", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "jest-util": "^27.4.2", - "string-length": "^4.0.1" + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" } }, - "jest-worker": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.4.5.tgz", - "integrity": "sha512-f2s8kEdy15cv9r7q4KkzGXvlY0JTcmCbMHZBfSQDwW77REr45IDWwd0lksDFeVHH2jJ5pqb90T77XscrjeGzzg==", + "node_modules/jackspeak": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.0.tgz", + "integrity": "sha512-9DDdhb5j6cpeitCbvLO7n7J4IxnbM6hoF6O1g4HQ5TfhvvKN8ywDM7668ZhMHRqVmxqhps/F6syWK2KcPxYlkw==", "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, + "license": "BlueOak-1.0.0", "dependencies": { - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "joycon": { + "node_modules/joycon": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "license": "MIT" }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "jsdom": { - "version": "16.7.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", - "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", - "dev": true, - "requires": { - "abab": "^2.0.5", - "acorn": "^8.2.4", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.3.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.1", - "domexception": "^2.0.1", - "escodegen": "^2.0.0", - "form-data": "^3.0.0", - "html-encoding-sniffer": "^2.0.1", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.0", - "parse5": "6.0.1", - "saxes": "^5.0.1", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.1.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.5.0", - "ws": "^7.4.6", - "xml-name-validator": "^3.0.0" - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "json-parse-better-errors": { + "node_modules/json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true + "dev": true, + "license": "MIT" }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "node_modules/json-schema-ref-resolver": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-schema-ref-resolver/-/json-schema-ref-resolver-1.0.1.tgz", + "integrity": "sha512-EJAj1pgHc1hxF6vo2Z3s69fMjO1INq6eGHXZ8Z6wCQeldCuwxGK9Sxf4/cScGn3FZubCVUehfWtcDM/PLteCQw==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + } }, - "json-schema-resolver": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/json-schema-resolver/-/json-schema-resolver-1.3.0.tgz", - "integrity": "sha512-EX7W1r8aZ/T3j8GbbBxPXi60bnsELfT90OiA1QrbGMvwzVSbyMNOAzvMFcFb8m7gKCXZLJpGe+cJOvWgoFl29A==", - "dev": true, - "requires": { + "node_modules/json-schema-resolver": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/json-schema-resolver/-/json-schema-resolver-2.0.0.tgz", + "integrity": "sha512-pJ4XLQP4Q9HTxl6RVDLJ8Cyh1uitSs0CzDBAz1uoJ4sRD/Bk7cFSXL1FUXDW3zJ7YnfliJx6eu8Jn283bpZ4Yg==", + "license": "MIT", + "dependencies": { "debug": "^4.1.1", "rfdc": "^1.1.4", "uri-js": "^4.2.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/Eomm/json-schema-resolver?sponsor=1" } }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "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" }, - "json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dev": true, - "requires": { - "minimist": "^1.2.5" + "node_modules/jsox": { + "version": "1.2.121", + "resolved": "https://registry.npmjs.org/jsox/-/jsox-1.2.121.tgz", + "integrity": "sha512-9Ag50tKhpTwS6r5wh3MJSAvpSof0UBr39Pto8OnzFT32Z/pAbxAsKHzyvsyMEHVslELvHyO/4/jaQELHk8wDcw==", + "license": "MIT", + "bin": { + "jsox": "lib/cli.js" } }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "node_modules/junk": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/junk/-/junk-4.0.1.tgz", + "integrity": "sha512-Qush0uP+G8ZScpGMZvHUiRfI0YBWuB3gVBYlI0v0vvOJt5FLicco+IkP0a50LqTTQhmts/m6tP5SWE+USyIvcQ==", "dev": true, - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" + "license": "MIT", + "engines": { + "node": ">=12.20" }, - "dependencies": { - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true - } - } - }, - "junk": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/junk/-/junk-4.0.0.tgz", - "integrity": "sha512-ojtSU++zLJ3jQG9bAYjg94w+/DOJtRyD7nPaerMFrBhmdVmiV5/exYH5t4uHga4G/95nT6hr1OJoKIFbYbrW5w==", - "dev": true - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true - }, - "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==", - "dev": true - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "libpg-query": { - "version": "13.2.4", - "resolved": "https://registry.npmjs.org/libpg-query/-/libpg-query-13.2.4.tgz", - "integrity": "sha512-Tqg/9av8vzBYIpf9nuNnZnPepVtynFGqhGVpFP8nzc5fK2EFHs0kJfRZiFqhkswxj0gXV0esc37sfGoYLBgJUQ==", - "requires": { + "node_modules/libpg-query": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/libpg-query/-/libpg-query-13.3.2.tgz", + "integrity": "sha512-6ft2qyk+LO1hdmPU389RvN7inRGLU0T8Ge4RG+q4usE+dAA4nl+WVp4HVpBC+1Ku4lgxM38PkoW7OzAw8VDebA==", + "hasInstallScript": true, + "license": "LICENSE IN LICENSE", + "dependencies": { "@mapbox/node-pre-gyp": "^1.0.8", - "aws-sdk": "^2.1076.0", "node-addon-api": "^1.6.3", "node-gyp": "^8.0.0" } }, - "light-my-request": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-4.7.0.tgz", - "integrity": "sha512-LTa8YZp3K2AUpqUnwwKajoIHcsKOBnzwJNQSrk7unziPwo6CjOYjyO0F9wfkxFvP+nBsCGe3eMPnedVgIIgdAw==", - "dev": true, - "requires": { - "ajv": "^8.1.0", - "cookie": "^0.4.0", - "fastify-warning": "^0.2.0", - "set-cookie-parser": "^2.4.1" - }, + "node_modules/light-my-request": { + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-5.14.0.tgz", + "integrity": "sha512-aORPWntbpH5esaYpGOOmri0OHDOe3wC5M2MQxZ9dvMLZm6DnaAn0kJlcbU9hwsQgLzmZyReKwFwwPkR+nHu5kA==", + "license": "BSD-3-Clause", "dependencies": { - "ajv": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.8.2.tgz", - "integrity": "sha512-x9VuX+R/jcFj1DHo/fCp99esgGDWiHENrKxaCENuCxpoMCmAt/COCGVDwA7kleEpEzJjDnvh3yGoOuLu0Dtllw==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "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==", - "dev": true - } + "cookie": "^0.7.0", + "process-warning": "^3.0.0", + "set-cookie-parser": "^2.4.1" } }, - "lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "load-json-file": { + "node_modules/load-json-file": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "graceful-fs": "^4.1.2", "parse-json": "^4.0.0", "pify": "^3.0.0", "strip-bom": "^3.0.0" }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - } + "engines": { + "node": ">=4" } }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "node_modules/loupe": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.3.tgz", + "integrity": "sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==", "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", - "dev": true + "license": "MIT" }, - "lru-cache": { + "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { + "license": "ISC", + "dependencies": { "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" } }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "requires": { - "semver": "^6.0.0" - }, + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "dev": true, + "license": "MIT", "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/magicast": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz", + "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.25.4", + "@babel/types": "^7.25.4", + "source-map-js": "^1.2.0" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "make-error": { + "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true + "dev": true, + "license": "ISC" }, - "make-fetch-happen": { + "node_modules/make-fetch-happen": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", - "requires": { + "license": "ISC", + "dependencies": { "agentkeepalive": "^4.1.3", "cacache": "^15.2.0", "http-cache-semantics": "^4.1.0", @@ -4007,354 +5102,325 @@ "promise-retry": "^2.0.1", "socks-proxy-agent": "^6.0.0", "ssri": "^8.0.0" + }, + "engines": { + "node": ">= 10" } }, - "makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "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==", "dev": true, - "requires": { - "tmpl": "1.0.5" + "license": "MIT", + "engines": { + "node": ">= 0.4" } }, - "map-obj": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", - "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", - "dev": true - }, - "memorystream": { + "node_modules/memorystream": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", - "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=", - "dev": true - }, - "meow": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/meow/-/meow-10.1.2.tgz", - "integrity": "sha512-zbuAlN+V/sXlbGchNS9WTWjUzeamwMt/BApKCJi7B0QyZstZaMx0n4Unll/fg0njGtMdC9UP5SAscvOCLYdM+Q==", - "dev": true, - "requires": { - "@types/minimist": "^1.2.2", - "camelcase-keys": "^7.0.0", - "decamelize": "^5.0.0", - "decamelize-keys": "^1.1.0", - "hard-rejection": "^2.1.0", - "minimist-options": "4.1.0", - "normalize-package-data": "^3.0.2", - "read-pkg-up": "^8.0.0", - "redent": "^4.0.0", - "trim-newlines": "^4.0.2", - "type-fest": "^1.2.2", - "yargs-parser": "^20.2.9" - }, - "dependencies": { - "decamelize": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-5.0.1.tgz", - "integrity": "sha512-VfxadyCECXgQlkoEAjeghAr5gY3Hf+IKjKb+X8tGVDtveCjN+USwprd2q3QXBR9T1+x2DG0XZF5/w+7HAtSaXA==", - "dev": true - }, - "hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "normalize-package-data": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", - "dev": true, - "requires": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" - } - }, - "type-fest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", - "dev": true - } + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "dev": true, + "engines": { + "node": ">= 0.10.0" } }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true + "node_modules/meow": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz", + "integrity": "sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "merge2": { + "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" + "license": "MIT", + "engines": { + "node": ">= 8" } }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true - }, - "mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", - "dev": true - }, - "mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, - "requires": { - "mime-db": "1.51.0" + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" } }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "mimic-response": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", - "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", - "dev": true - }, - "min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" - }, - "minimist-options": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", - "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", - "dev": true, - "requires": { - "arrify": "^1.0.1", - "is-plain-obj": "^1.1.0", - "kind-of": "^6.0.3" }, - "dependencies": { - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "dev": true - } + "engines": { + "node": "*" } }, - "minipass": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz", - "integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==", - "requires": { + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "dependencies": { "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "minipass-collect": { + "node_modules/minipass-collect": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", - "requires": { + "license": "ISC", + "dependencies": { "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" } }, - "minipass-fetch": { + "node_modules/minipass-fetch": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", - "requires": { - "encoding": "^0.1.12", + "license": "MIT", + "dependencies": { "minipass": "^3.1.0", "minipass-sized": "^1.0.3", "minizlib": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "optionalDependencies": { + "encoding": "^0.1.12" } }, - "minipass-flush": { + "node_modules/minipass-flush": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "requires": { + "license": "ISC", + "dependencies": { "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" } }, - "minipass-pipeline": { + "node_modules/minipass-pipeline": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "requires": { + "license": "ISC", + "dependencies": { "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" } }, - "minipass-sized": { + "node_modules/minipass-sized": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "requires": { + "license": "ISC", + "dependencies": { "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" } }, - "minizlib": { + "node_modules/minizlib": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "requires": { + "license": "MIT", + "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" } }, - "mkdirp": { + "node_modules/mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" - }, - "mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "dev": true + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } }, - "mri": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.4.tgz", - "integrity": "sha512-6y7IjGPm8AzlvoUrwAaw1tLnUBudaS3752vcd8JtrpGGQn+rXIe63LFVHm/YMwtqAuh+LJPCFdlLYPWM1nYn6w==", - "dev": true + "node_modules/mnemonist": { + "version": "0.39.6", + "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.39.6.tgz", + "integrity": "sha512-A/0v5Z59y63US00cRSLiloEIw3t5G+MiKz4BhX21FI+YBJXBOGW0ohFxTxO08dsOYlzxo87T7vGfZKYp2bcAWA==", + "license": "MIT", + "dependencies": { + "obliterator": "^2.0.1" + } }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "node_modules/module-details-from-path": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.3.tgz", + "integrity": "sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A==", + "license": "MIT" }, - "multistream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/multistream/-/multistream-4.1.0.tgz", - "integrity": "sha512-J1XDiAmmNpRCBfIWJv+n0ymC4ABcf/Pl+5YvC5B/D2f/2+8PtHvCNxMPKiQcZyi922Hq69J2YOpb1pTywfifyw==", - "dev": true, - "requires": { - "once": "^1.4.0", - "readable-stream": "^3.6.0" + "node_modules/moo": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz", + "integrity": "sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==", + "license": "BSD-3-Clause" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", - "dev": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true + "node_modules/nearley": { + "version": "2.20.1", + "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.20.1.tgz", + "integrity": "sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ==", + "license": "MIT", + "dependencies": { + "commander": "^2.19.0", + "moo": "^0.5.0", + "railroad-diagrams": "^1.0.0", + "randexp": "0.4.6" + }, + "bin": { + "nearley-railroad": "bin/nearley-railroad.js", + "nearley-test": "bin/nearley-test.js", + "nearley-unparse": "bin/nearley-unparse.js", + "nearleyc": "bin/nearleyc.js" + }, + "funding": { + "type": "individual", + "url": "https://nearley.js.org/#give-to-nearley" + } }, - "negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + "node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } }, - "nested-error-stacks": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz", - "integrity": "sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==", - "dev": true + "node_modules/nested-error-stacks": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz", + "integrity": "sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==", + "dev": true, + "license": "MIT" }, - "nice-try": { + "node_modules/nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "node-abi": { - "version": "2.30.1", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz", - "integrity": "sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w==", "dev": true, - "requires": { - "semver": "^5.4.1" - }, + "license": "MIT" + }, + "node_modules/node-abi": { + "version": "3.74.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.74.0.tgz", + "integrity": "sha512-c5XK0MjkGBrQPGYG24GBADZud0NCbznxNx0ZkS+ebUTrmV1qTDxPxSL8zEAPURXSbLRWVexxmP4986BziahL5w==", + "license": "MIT", "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" } }, - "node-addon-api": { + "node_modules/node-addon-api": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz", - "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==" - }, - "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "requires": { + "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==", + "license": "MIT" + }, + "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" }, - "dependencies": { - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true } } }, - "node-gyp": { + "node_modules/node-gyp": { "version": "8.4.1", "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", - "requires": { + "license": "MIT", + "dependencies": { "env-paths": "^2.2.0", "glob": "^7.1.4", "graceful-fs": "^4.2.6", @@ -4366,104 +5432,213 @@ "tar": "^6.1.2", "which": "^2.0.2" }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": ">= 10.12.0" + } + }, + "node_modules/node-gyp/node_modules/are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/node-gyp/node_modules/gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/node-gyp/node_modules/npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/node-gyp/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-gyp/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/node-sql-parser": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/node-sql-parser/-/node-sql-parser-4.18.0.tgz", + "integrity": "sha512-2YEOR5qlI1zUFbGMLKNfsrR5JUvFg9LxIRVE+xJe962pfVLH0rnItqLzv96XVs1Y1UIR8FxsXAuvX/lYAWZ2BQ==", + "license": "Apache-2.0", "dependencies": { - "are-we-there-yet": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.0.tgz", - "integrity": "sha512-0GWpv50YSOcLXaN6/FAKY3vfRbllXWV2xvfA/oKJF8pzFhWXPV+yjhJXDBbjscDYowv7Yw1A3uigpzn5iEGTyw==", - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - } - }, - "gauge": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.3.tgz", - "integrity": "sha512-ICw1DhAwMtb22rYFwEHgJcx1JCwJGv3x6G0OQUq56Nge+H4Q8JEwr8iveS0XFlsUNSI67F5ffMGK25bK4Pmskw==", - "requires": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" - } - }, - "npmlog": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.1.tgz", - "integrity": "sha512-BTHDvY6nrRHuRfyjt1MAufLxYdVXZfd099H4+i1f0lPywNQyI4foeNXJRObB/uy+TYqUW0vAD9gbdSOXPst7Eg==", - "requires": { - "are-we-there-yet": "^3.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^4.0.0", - "set-blocking": "^2.0.0" - } - } + "big-integer": "^1.6.48" + }, + "engines": { + "node": ">=8" } }, - "node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", - "dev": true + "node_modules/nodemon": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.9.tgz", + "integrity": "sha512-hdr1oIb2p6ZSxu3PB2JWWYS7ZQ0qvaZsc3hK8DR8f02kRzc8rjYmxAIvdz+aYC+8F2IjNaB7HMcSDg8nQpJxyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } }, - "node-releases": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz", - "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==", - "dev": true + "node_modules/nodemon/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } }, - "node-sql-parser": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/node-sql-parser/-/node-sql-parser-4.0.3.tgz", - "integrity": "sha512-OySEmtUfwQbXDJiN4t6lQdAh9PNg5P2cE8l3KtOqGarVHDnJUK80miGP9lAc/IzVvKstvKvc0VY0XN2DIcl1RQ==", - "requires": { - "big-integer": "^1.6.48" + "node_modules/nodemon/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" } }, - "nopt": { + "node_modules/nopt": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "requires": { + "license": "ISC", + "dependencies": { "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" } }, - "normalize-package-data": { + "node_modules/normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, - "requires": { + "license": "BSD-2-Clause", + "dependencies": { "hosted-git-info": "^2.1.4", "resolve": "^1.10.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } } }, - "normalize-path": { + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "npm-run-all": { + "node_modules/npm-run-all": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "ansi-styles": "^3.2.1", "chalk": "^2.4.1", "cross-spawn": "^6.0.5", @@ -4474,2313 +5649,3053 @@ "shell-quote": "^1.6.1", "string.prototype.padend": "^3.0.0" }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" + "bin": { + "npm-run-all": "bin/npm-run-all/index.js", + "run-p": "bin/run-p/index.js", + "run-s": "bin/run-s/index.js" + }, + "engines": { + "node": ">= 4" } }, - "npmlog": { + "node_modules/npmlog": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", - "requires": { + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { "are-we-there-yet": "^2.0.0", "console-control-strings": "^1.1.0", "gauge": "^3.0.0", "set-blocking": "^2.0.0" } }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true - }, - "nwsapi": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", - "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", - "dev": true - }, - "object-assign": { + "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "object-inspect": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.1.tgz", - "integrity": "sha512-If7BjFlpkzzBeV1cqgT3OSWT3azyoxDGajR+iGnFBfVV2EWyDyWaZZW2ERDjUaY2QM8i5jI3Sj7mhsM4DDAqWA==", - "dev": true + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "object-keys": { + "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==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } }, - "object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "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==", "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "on-exit-leak-free": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-0.2.0.tgz", - "integrity": "sha512-dqaz3u44QbRXQooZLTUKU41ZrzYrcvLISVgbrzbyCMxpmSLJvZ3ZamIJIZ29P6OhZIkNIQKosdeM6t1LYbA9hg==" + "node_modules/obliterator": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.5.tgz", + "integrity": "sha512-42CPE9AhahZRsMNslczq0ctAEtqk8Eka26QofnqC346BZdHDySk3LWka23LI7ULIw11NmltpiLagIq8gBozxTw==", + "license": "MIT" }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "dev": true, - "requires": { - "ee-first": "1.1.1" + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "license": "MIT" + }, + "node_modules/on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" } }, - "once": { + "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { "wrappy": "1" } }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "openapi-types": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-10.0.0.tgz", - "integrity": "sha512-Y8xOCT2eiKGYDzMW9R4x5cmfc3vGaaI4EL2pwhDmodWw1HlK18YcZ4uJxc7Rdp7/gGzAygzH9SXr6GKYIXbRcQ==", - "dev": true + "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" }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "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==", "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "p-event": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz", - "integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==", + "node_modules/p-event": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-5.0.1.tgz", + "integrity": "sha512-dd589iCQ7m1L0bmC5NLlVYfy3TbBEsMUfWx9PyAgPeIcFZ/E2yaTZ4Rz4MiBmmJShviiftHVXOqfnfzJ6kyMrQ==", "dev": true, - "requires": { - "p-timeout": "^3.1.0" + "license": "MIT", + "dependencies": { + "p-timeout": "^5.0.2" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "p-filter": { + "node_modules/p-filter": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-3.0.0.tgz", "integrity": "sha512-QtoWLjXAW++uTX67HZQz1dbTpqBfiidsB6VtQUC9iR85S120+s0T5sO6s+B5MLzFcZkrEd/DGMmCjR+f2Qpxwg==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "p-map": "^5.1.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true + "node_modules/p-filter/node_modules/aggregate-error": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-4.0.1.tgz", + "integrity": "sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==", + "dev": true, + "license": "MIT", + "dependencies": { + "clean-stack": "^4.0.0", + "indent-string": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "p-is-promise": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-3.0.0.tgz", - "integrity": "sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==", - "dev": true + "node_modules/p-filter/node_modules/clean-stack": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-4.2.0.tgz", + "integrity": "sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "node_modules/p-filter/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", "dev": true, - "requires": { - "yocto-queue": "^0.1.0" + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "node_modules/p-filter/node_modules/indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", "dev": true, - "requires": { - "p-limit": "^2.2.0" + "license": "MIT", + "engines": { + "node": ">=12" }, - "dependencies": { - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "p-map": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-5.3.0.tgz", - "integrity": "sha512-SRbIQFoLYNezHkqZslqeg963HYUtqOrfMCxjNrFOpJ19WTYuq26rQoOXeX8QQiMLUlLqdYV/7PuDsdYJ7hLE1w==", + "node_modules/p-filter/node_modules/p-map": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-5.5.0.tgz", + "integrity": "sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "aggregate-error": "^4.0.0" }, - "dependencies": { - "aggregate-error": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-4.0.0.tgz", - "integrity": "sha512-8DGp7zUt1E9k0NE2q4jlXHk+V3ORErmwolEdRz9iV+LKJ40WhMHh92cxAvhqV2I+zEn/gotIoqoMs0NjF3xofg==", - "dev": true, - "requires": { - "clean-stack": "^4.0.0", - "indent-string": "^5.0.0" - } - }, - "clean-stack": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-4.1.0.tgz", - "integrity": "sha512-dxXQYI7mfQVcaF12s6sjNFoZ6ZPDQuBBLp3QJ5156k9EvUFClUoZ11fo8HnLQO241DDVntHEug8MOuFO5PSfRg==", - "dev": true, - "requires": { - "escape-string-regexp": "5.0.0" - } - }, - "escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", - "dev": true - }, - "indent-string": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", - "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", - "dev": true - } + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "p-timeout": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", - "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "node_modules/p-map": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-6.0.0.tgz", + "integrity": "sha512-T8BatKGY+k5rU+Q/GTYgrEf2r4xRMevAN5mtXc2aPc4rS1j3s+vWTaO2Wag94neXuCAUAs8cxBL9EeB5EA6diw==", "dev": true, - "requires": { - "p-finally": "^1.0.0" + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true + "node_modules/p-timeout": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-5.1.0.tgz", + "integrity": "sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "packet-reader": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", - "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" }, - "parse-json": { + "node_modules/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "error-ex": "^1.3.1", "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" } }, - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-is-absolute": { + "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true + "node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } }, - "path-parse": { + "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "license": "MIT" }, - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "node_modules/path-scurry": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", "dev": true, - "requires": { - "pify": "^3.0.0" - }, + "license": "BlueOak-1.0.0", "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - } + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.1.0.tgz", + "integrity": "sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==", + "dev": true, + "license": "ISC", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/path-scurry/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", + "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" } }, - "pg": { - "version": "8.7.3", - "resolved": "https://registry.npmjs.org/pg/-/pg-8.7.3.tgz", - "integrity": "sha512-HPmH4GH4H3AOprDJOazoIcpI49XFsHCe8xlrjHkWiapdbHK+HLtbm/GQzXYAZwmPju/kzKhjaSfMACG+8cgJcw==", - "requires": { - "buffer-writer": "2.0.0", - "packet-reader": "1.0.0", - "pg-connection-string": "^2.5.0", - "pg-pool": "^3.5.1", - "pg-protocol": "^1.5.0", + "node_modules/pg": { + "name": "@supabase/pg", + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@supabase/pg/-/pg-0.0.3.tgz", + "integrity": "sha512-WW4VdNYQocmcg7dZYk92vHY2nhhMhxoJhZ20m7PzuKe8p4vSdkv2tSM8HUCpZDiLxC6djfVeMk39ukcwEpFdzg==", + "license": "MIT", + "dependencies": { + "pg-connection-string": "^2.7.0", + "pg-pool": "^3.8.0", + "pg-protocol": "npm:@supabase/pg-protocol@^0.0.2", "pg-types": "^2.1.0", "pgpass": "1.x" + }, + "engines": { + "node": ">= 8.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.1.1" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } } }, - "pg-connection-string": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", - "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==" + "node_modules/pg-cloudflare": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", + "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", + "license": "MIT", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.7.0.tgz", + "integrity": "sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA==", + "license": "MIT" }, - "pg-format": { + "node_modules/pg-format": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/pg-format/-/pg-format-1.0.4.tgz", - "integrity": "sha1-J3NCNsKtP05QZJFaWTNOIAQKgo4=" + "integrity": "sha512-YyKEF78pEA6wwTAqOUaHIN/rWpfzzIuMh9KdAhc3rSLQ/7zkRFcCgYBAEGatDstLyZw4g0s9SNICmaTGnBVeyw==", + "license": "MIT", + "engines": { + "node": ">=4.0" + } }, - "pg-int8": { + "node_modules/pg-int8": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", - "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "license": "ISC", + "engines": { + "node": ">=4.0.0" + } }, - "pg-pool": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.5.1.tgz", - "integrity": "sha512-6iCR0wVrro6OOHFsyavV+i6KYL4lVNyYAB9RD18w66xSzN+d8b66HiwuP30Gp1SH5O9T82fckkzsRjlrhD0ioQ==" + "node_modules/pg-numeric": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pg-numeric/-/pg-numeric-1.0.2.tgz", + "integrity": "sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==", + "license": "ISC", + "engines": { + "node": ">=4" + } }, - "pg-protocol": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz", - "integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==" + "node_modules/pg-protocol": { + "name": "@supabase/pg-protocol", + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@supabase/pg-protocol/-/pg-protocol-0.0.2.tgz", + "integrity": "sha512-OLp5LeWRmfJy4vwV753hsCE90vzNSTSAwhsbinCIeoT455DHBufrkktVc4YvPXYEFj+EzpVKw/N0piX+AvBMBg==", + "license": "MIT" + }, + "node_modules/pg-types": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-4.0.2.tgz", + "integrity": "sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==", + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "pg-numeric": "1.0.2", + "postgres-array": "~3.0.1", + "postgres-bytea": "~3.0.0", + "postgres-date": "~2.1.0", + "postgres-interval": "^3.0.0", + "postgres-range": "^1.1.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/pg/node_modules/pg": { + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.14.1.tgz", + "integrity": "sha512-0TdbqfjwIun9Fm/r89oB7RFQ0bLgduAhiIqIXOsyKoiC/L54DbuAAzIEN/9Op0f1Po9X7iCPXGoa/Ah+2aI8Xw==", + "license": "MIT", + "peer": true, + "dependencies": { + "pg-connection-string": "^2.7.0", + "pg-pool": "^3.8.0", + "pg-protocol": "^1.8.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + }, + "engines": { + "node": ">= 8.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.1.1" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg/node_modules/pg-pool": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.8.0.tgz", + "integrity": "sha512-VBw3jiVm6ZOdLBTIcXLNdSotb6Iy3uOCwDGFAksZCXmi10nyRvnP2v3jl4d+IsLYRyXf6o9hIm/ZtUzlByNUdw==", + "license": "MIT", + "peerDependencies": { + "pg": ">=8.0" + } }, - "pg-types": { + "node_modules/pg/node_modules/pg-types": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", - "requires": { + "license": "MIT", + "dependencies": { "pg-int8": "1.0.1", "postgres-array": "~2.0.0", "postgres-bytea": "~1.0.0", "postgres-date": "~1.0.4", "postgres-interval": "^1.1.0" }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pg/node_modules/pg/node_modules/pg-protocol": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.8.0.tgz", + "integrity": "sha512-jvuYlEkL03NRvOoyoRktBK7+qU5kOvlAwvmrH8sr3wbLrOdVWsRxQfz8mMy9sZFsqJ1hEWNfdWKI4SAmoL+j7g==", + "license": "MIT", + "peer": true + }, + "node_modules/pg/node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/pg/node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pg/node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pg/node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "license": "MIT", "dependencies": { - "postgres-array": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", - "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" - } + "split2": "^4.1.0" } }, - "pgpass": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.4.tgz", - "integrity": "sha512-YmuA56alyBq7M59vxVBfPJrGSozru8QAdoNlWuW3cz8l+UX3cWge0vTvjKhsSHSJpo3Bom8/Mm6hf0TR5GY0+w==", - "requires": { - "split2": "^3.1.1" - } - }, - "pgsql-deparser": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/pgsql-deparser/-/pgsql-deparser-13.3.0.tgz", - "integrity": "sha512-TdXQaTfm0CtT0YFxjALtT7Top4sJlm2m7ENd27yZpAZvFlECWrwzeLDjGGiqNzuxco+6IcEFQ6o1zMkPA8rfXQ==", - "requires": { - "@babel/runtime": "^7.11.2", + "node_modules/pgsql-deparser": { + "version": "13.15.0", + "resolved": "https://registry.npmjs.org/pgsql-deparser/-/pgsql-deparser-13.15.0.tgz", + "integrity": "sha512-6d4YeDE/y+AZ/C4tlzTrFwbOqDW4ma/jvYlXRgXYVdPU2WF5IQISksIQ8uhNMXW7QxL/4gw0bzLhRNwckf3t/Q==", + "license": "SEE LICENSE IN LICENSE", + "dependencies": { + "@pgsql/types": "^13.9.0", "dotty": "^0.1.0", - "lodash": "^4.17.20", - "pgsql-enums": "^13.1.2" + "pgsql-enums": "^13.10.0" } }, - "pgsql-enums": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/pgsql-enums/-/pgsql-enums-13.1.2.tgz", - "integrity": "sha512-uzYVwJkh4zcuWknamZ18cj3K7uyWiL4kdcZn99N4doDOv/3RKlBDSeGhiUjhZQo6sA3VWSYQXy6/4Qltl00zSw==", - "requires": { - "@babel/runtime": "^7.4.2" - } + "node_modules/pgsql-enums": { + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/pgsql-enums/-/pgsql-enums-13.10.0.tgz", + "integrity": "sha512-L0vO9RwwPENvB07YlIVTnRu3JMnmjHQhxWR2NQbHOUPIpfF6khhfv+OC51By2ATts3jfZRSi8TLjNf9O6rP9iA==", + "license": "SEE LICENSE IN LICENSE" }, - "pgsql-parser": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/pgsql-parser/-/pgsql-parser-13.3.0.tgz", - "integrity": "sha512-wkef6kZh6u7WU8X4UMdJo3TT7j6bND1c3ac4d1hrpU5ep9UQUAvJYNrNEBJponJ7xctdjsSfWN0WVv45pZ7kCw==", - "requires": { - "@babel/runtime": "^7.11.2", - "libpg-query": "13.2.4", - "minimist": "^1.2.5", - "pgsql-deparser": "^13.3.0", - "pgsql-enums": "^13.1.2" + "node_modules/pgsql-parser": { + "version": "13.16.0", + "resolved": "https://registry.npmjs.org/pgsql-parser/-/pgsql-parser-13.16.0.tgz", + "integrity": "sha512-LdHFWjotgN7y2rEAb2K/LeLZrMJvpLy0Qe+1+8ZByf5C2pmKTo98VXiVfGpxC6vkfWgP9VsT4vYQ4ZlQexHcHw==", + "license": "SEE LICENSE IN LICENSE", + "dependencies": { + "libpg-query": "13.3.2", + "minimist": "^1.2.6", + "pgsql-deparser": "^13.15.0", + "pgsql-enums": "^13.10.0" + }, + "bin": { + "pgsql-parser": "main/cli.js" } }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" }, - "picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "dev": true + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } }, - "pidtree": { + "node_modules/pidtree": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", - "dev": true - }, - "pino": { - "version": "7.9.1", - "resolved": "https://registry.npmjs.org/pino/-/pino-7.9.1.tgz", - "integrity": "sha512-28+D7c5orCoScdcWtiPXrCA9tdVosBWrYQgVtPdYTyiuTt6u/+rbEtpJR+dtVG8k1flhv0H2f0XSkgGm+TdjqQ==", - "requires": { - "fast-redact": "^3.0.0", - "on-exit-leak-free": "^0.2.0", - "pino-abstract-transport": "v0.5.0", - "pino-std-serializers": "^4.0.0", - "process-warning": "^1.0.0", + "dev": true, + "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/pino": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-9.6.0.tgz", + "integrity": "sha512-i85pKRCt4qMjZ1+L7sy2Ag4t1atFcdbEt76+7iRJn1g2BvsnRMGu9p8pivl9fs63M2kF/A0OacFZhTub+m/qMg==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0", + "fast-redact": "^3.1.1", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^2.0.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^4.0.0", "quick-format-unescaped": "^4.0.3", - "real-require": "^0.1.0", - "safe-stable-stringify": "^2.1.0", - "sonic-boom": "^2.2.1", - "thread-stream": "^0.13.0" - } - }, - "pino-abstract-transport": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-0.5.0.tgz", - "integrity": "sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ==", - "requires": { - "duplexify": "^4.1.2", - "split2": "^4.0.0" + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^4.0.1", + "thread-stream": "^3.0.0" }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz", + "integrity": "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==", + "license": "MIT", "dependencies": { - "split2": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz", - "integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==" - } + "split2": "^4.0.0" } }, - "pino-pretty": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-7.5.4.tgz", - "integrity": "sha512-p5AuDpsesgCiEE+8veQTOcuHBdj/BsAMntpDQeTJ0vAcsIGufR3WnKAXbjaELfEp1UYBD+ewAPb1EmIcfVXl6w==", + "node_modules/pino-pretty": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-12.1.0.tgz", + "integrity": "sha512-Z7JdCPqggoRyo0saJyCe1BN8At5qE+ZBElNbyx+znCaCVN+ohOqlWb+/WSYnamzfi2e6P6pXq/3H66KwFQHXWg==", "dev": true, - "requires": { - "args": "^5.0.1", + "license": "MIT", + "dependencies": { "colorette": "^2.0.7", "dateformat": "^4.6.3", - "fast-safe-stringify": "^2.0.7", + "fast-copy": "^3.0.2", + "fast-safe-stringify": "^2.1.1", + "help-me": "^5.0.0", "joycon": "^3.1.1", - "on-exit-leak-free": "^0.2.0", - "pino-abstract-transport": "^0.5.0", + "minimist": "^1.2.6", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^2.0.0", "pump": "^3.0.0", - "readable-stream": "^3.6.0", - "rfdc": "^1.3.0", + "readable-stream": "^4.0.0", "secure-json-parse": "^2.4.0", - "sonic-boom": "^2.2.0", + "sonic-boom": "^4.0.1", "strip-json-comments": "^3.1.1" + }, + "bin": { + "pino-pretty": "bin.js" } }, - "pino-std-serializers": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-4.0.0.tgz", - "integrity": "sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q==" + "node_modules/pino-pretty/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "dev": true, + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } }, - "pirates": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.4.tgz", - "integrity": "sha512-ZIrVPH+A52Dw84R0L3/VS9Op04PuQ2SEoJL6bkshmiTic/HldyW9Tf7oH5mhJZBK7NmDx27vSMrYEXPXclpDKw==", - "dev": true - }, - "pkg": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/pkg/-/pkg-5.5.2.tgz", - "integrity": "sha512-pD0UB2ud01C6pVv2wpGsTYJrXI/bnvGRYvMLd44wFzA1p+A2jrlTGFPAYa7YEYzmitXhx23PqalaG1eUEnSwcA==", - "dev": true, - "requires": { - "@babel/parser": "7.16.2", - "@babel/types": "7.16.0", - "chalk": "^4.1.2", - "escodegen": "^2.0.0", - "fs-extra": "^9.1.0", - "globby": "^11.0.4", - "into-stream": "^6.0.0", - "minimist": "^1.2.5", - "multistream": "^4.1.0", - "pkg-fetch": "3.2.6", - "prebuild-install": "6.1.4", - "progress": "^2.0.3", - "resolve": "^1.20.0", - "stream-meter": "^1.0.4", - "tslib": "2.3.1" - }, - "dependencies": { - "@babel/parser": { - "version": "7.16.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.2.tgz", - "integrity": "sha512-RUVpT0G2h6rOZwqLDTrKk7ksNv7YpAilTnYe1/Q+eDjxEceRMKVWbCsX7t8h6C1qCFi/1Y8WZjcEPBAFG27GPw==", - "dev": true - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "globby": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", - "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - } + "node_modules/pino-std-serializers": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.0.0.tgz", + "integrity": "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==", + "license": "MIT" + }, + "node_modules/pino/node_modules/process-warning": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-4.0.1.tgz", + "integrity": "sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" } - } + ], + "license": "MIT" }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "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==", "dev": true, - "requires": { - "find-up": "^4.0.0" + "license": "MIT", + "engines": { + "node": ">= 0.4" } }, - "pkg-fetch": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/pkg-fetch/-/pkg-fetch-3.2.6.tgz", - "integrity": "sha512-Q8fx6SIT022g0cdSE4Axv/xpfHeltspo2gg1KsWRinLQZOTRRAtOOaEFghA1F3jJ8FVsh8hGrL/Pb6Ea5XHIFw==", + "node_modules/postcss": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", + "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", "dev": true, - "requires": { - "chalk": "^4.1.2", - "fs-extra": "^9.1.0", - "https-proxy-agent": "^5.0.0", - "node-fetch": "^2.6.6", - "progress": "^2.0.3", - "semver": "^7.3.5", - "tar-fs": "^2.1.1", - "yargs": "^16.2.0" + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.8", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" } }, - "postgres-array": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.1.tgz", - "integrity": "sha512-h7i53Dw2Yq3a1uuZ6lbVFAkvMMwssJ8jkzeAg0XaZm1XIFF/t/s+tockdqbWTymyEm07dVenOQbFisEi+kj8uA==" + "node_modules/postgres-array": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.4.tgz", + "integrity": "sha512-nAUSGfSDGOaOAEGwqsRY27GPOea7CNipJPOA7lPbdEpx5Kg3qzdP0AaWC5MlhTWV9s4hFX39nomVZ+C4tnGOJQ==", + "license": "MIT", + "engines": { + "node": ">=12" + } }, - "postgres-bytea": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", - "integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=" + "node_modules/postgres-bytea": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-3.0.0.tgz", + "integrity": "sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==", + "license": "MIT", + "dependencies": { + "obuf": "~1.1.2" + }, + "engines": { + "node": ">= 6" + } }, - "postgres-date": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", - "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==" + "node_modules/postgres-date": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-2.1.0.tgz", + "integrity": "sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==", + "license": "MIT", + "engines": { + "node": ">=12" + } }, - "postgres-interval": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", - "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", - "requires": { - "xtend": "^4.0.0" + "node_modules/postgres-interval": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-3.0.0.tgz", + "integrity": "sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==", + "license": "MIT", + "engines": { + "node": ">=12" } }, - "prebuild-install": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.4.tgz", - "integrity": "sha512-Z4vpywnK1lBg+zdPCVCsKq0xO66eEV9rWo2zrROGGiRS4JtueBOdlB1FnY8lcy7JsUud/Q3ijUxyWN26Ika0vQ==", - "dev": true, - "requires": { - "detect-libc": "^1.0.3", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^2.21.0", - "npmlog": "^4.0.1", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^3.0.3", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" + "node_modules/postgres-range": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/postgres-range/-/postgres-range-1.1.4.tgz", + "integrity": "sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==", + "license": "MIT" + }, + "node_modules/prettier": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", + "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "dev": true - }, - "are-we-there-yet": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", - "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", - "dev": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "dev": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "dev": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "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" - } - }, - "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==", - "dev": true - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "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==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, - "prettier": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.0.tgz", - "integrity": "sha512-m2FgJibYrBGGgQXNzfd0PuDGShJgRavjUoRCw1mZERIWVSXF0iLzLm+aOqTAbLnC3n6JzUhAA8uZnFVghHJ86A==" - }, - "prettier-plugin-sql": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/prettier-plugin-sql/-/prettier-plugin-sql-0.4.1.tgz", - "integrity": "sha512-HSBn1f1ZbFIqWm9vVJcdQl1tzdh8qYZbBNK7z3iWhDO/DXM7gZH2HnS5r99e3tYqf34WIdo2nSCWaqylo+5fPw==", - "requires": { - "node-sql-parser": "^4.0.0", - "sql-formatter": "^4.0.2" - } - }, - "pretty-format": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.2.tgz", - "integrity": "sha512-p0wNtJ9oLuvgOQDEIZ9zQjZffK7KtyR6Si0jnXULIDwrlNF8Cuir3AZP0hHv0jmKuNN/edOnbMjnzd4uTcmWiw==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } + "node_modules/prettier-plugin-sql": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/prettier-plugin-sql/-/prettier-plugin-sql-0.17.1.tgz", + "integrity": "sha512-CR9UpTkUSC/f69AV597hnYcBo77iUhsBPkUER7BUa4YHRRtRUJGfL5LDoHAlUHWGTZNiJdHHELlzK6I3R9XuAw==", + "license": "MIT", + "dependencies": { + "jsox": "^1.2.118", + "node-sql-parser": "^4.11.0", + "sql-formatter": "^14.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + }, + "peerDependencies": { + "prettier": "^3.0.3" } }, - "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==", - "dev": true - }, - "process-warning": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-1.0.0.tgz", - "integrity": "sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q==" + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true + "node_modules/process-warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-3.0.0.tgz", + "integrity": "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==", + "license": "MIT" + }, + "node_modules/prom-client": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/prom-client/-/prom-client-14.2.0.tgz", + "integrity": "sha512-sF308EhTenb/pDRPakm+WgiN+VdM/T1RaHj1x+MvAuT8UiQP8JmOEbxVqtkbfR4LrvOg5n7ic01kRBDGXjYikA==", + "license": "Apache-2.0", + "dependencies": { + "tdigest": "^0.1.1" + }, + "engines": { + "node": ">=10" + } }, - "promise-inflight": { + "node_modules/promise-inflight": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=" + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "license": "ISC" }, - "promise-retry": { + "node_modules/promise-retry": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "requires": { + "license": "MIT", + "dependencies": { "err-code": "^2.0.2", "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" } }, - "prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - } - }, - "proxy-addr": { + "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==", - "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" } }, - "psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "node_modules/pump": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", + "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + "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" + } }, - "queue-microtask": { + "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==", - "dev": true + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" }, - "quick-format-unescaped": { + "node_modules/quick-format-unescaped": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", - "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==" - }, - "quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "dev": true - }, - "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==", - "dev": true + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "license": "MIT" }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, + "node_modules/railroad-diagrams": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz", + "integrity": "sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A==", + "license": "CC0-1.0" + }, + "node_modules/randexp": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.4.6.tgz", + "integrity": "sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==", + "license": "MIT", "dependencies": { - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true - } + "discontinuous-range": "1.0.0", + "ret": "~0.1.10" + }, + "engines": { + "node": ">=0.12" } }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true + "node_modules/randexp/node_modules/ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "license": "MIT", + "engines": { + "node": ">=0.12" + } }, - "read-pkg": { + "node_modules/read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "load-json-file": "^4.0.0", "normalize-package-data": "^2.3.2", "path-type": "^3.0.0" + }, + "engines": { + "node": ">=4" } }, - "read-pkg-up": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-8.0.0.tgz", - "integrity": "sha512-snVCqPczksT0HS2EC+SxUndvSzn6LRCwpfSvLrIfR5BKDQQZMaI6jPRC9dYvYFDRAuFEAnkwww8kBBNE/3VvzQ==", - "dev": true, - "requires": { - "find-up": "^5.0.0", - "read-pkg": "^6.0.0", - "type-fest": "^1.0.1" - }, - "dependencies": { - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "normalize-package-data": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", - "dev": true, - "requires": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "read-pkg": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-6.0.0.tgz", - "integrity": "sha512-X1Fu3dPuk/8ZLsMhEj5f4wFAF0DWoK7qhGJvgaijocXxBmSToKfbFtqbxMO7bVjNA1dmE5huAzjXj/ey86iw9Q==", - "dev": true, - "requires": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^3.0.2", - "parse-json": "^5.2.0", - "type-fest": "^1.0.1" - } - }, - "type-fest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", - "dev": true - } + "node_modules/read-pkg/node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" } }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { + "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==", + "license": "MIT", + "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" } }, - "readdirp": { + "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" } }, - "real-require": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.1.0.tgz", - "integrity": "sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg==" + "node_modules/real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } }, - "redent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-4.0.0.tgz", - "integrity": "sha512-tYkDkVVtYkSVhuQ4zBgfvciymHaeuel+zFKXShfDnFP5SyVEP7qo70Rf1jTOTCx3vGNAbnEi/xFkcfQVMIBWag==", + "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==", "dev": true, - "requires": { - "indent-string": "^5.0.0", - "strip-indent": "^4.0.0" - }, + "license": "MIT", "dependencies": { - "indent-string": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", - "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", - "dev": true - } + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "require-from-string": { + "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==", - "dev": true + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-in-the-middle": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-7.5.2.tgz", + "integrity": "sha512-gAZ+kLqBdHarXB64XpAe2VCjB7rIRv+mU8tfRWziHRJ5umKsIHN2tLLv6EtMw7WCdP19S0ERVMldNvxYCHnhSQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.5", + "module-details-from-path": "^1.0.3", + "resolve": "^1.22.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ret": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.4.3.tgz", + "integrity": "sha512-0f4Memo5QP7WQyUEAYUO3esD/XjOc3Zjjg5CPsAq1p8sIu0XPeMbHJemKA0BO7tV0X7+A0FoEpbmHXWxPyD3wQ==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "license": "MIT" + }, + "node_modules/rimraf": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.0.1.tgz", + "integrity": "sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^11.0.0", + "package-json-from-dist": "^1.0.0" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, - "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, - "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" } }, - "resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "node_modules/rimraf/node_modules/glob": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.1.tgz", + "integrity": "sha512-zrQDm8XPnYEKawJScsnM0QzobJxlT/kHOOlRTio8IH/GrmxRE5fjllkzdaHclIuNjUQTJYH2xHNIGfdpJkDJUw==", "dev": true, - "requires": { - "resolve-from": "^5.0.0" + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^4.0.1", + "minimatch": "^10.0.0", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true + "node_modules/rimraf/node_modules/minimatch": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", + "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/rollup": { + "version": "4.37.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.37.0.tgz", + "integrity": "sha512-iAtQy/L4QFU+rTJ1YUjXqJOJzuwEghqWzCEYD2FEghT7Gsy1VdABntrO4CLopA5IkflTyqNiLNwPcOJ3S7UKLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.6" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.37.0", + "@rollup/rollup-android-arm64": "4.37.0", + "@rollup/rollup-darwin-arm64": "4.37.0", + "@rollup/rollup-darwin-x64": "4.37.0", + "@rollup/rollup-freebsd-arm64": "4.37.0", + "@rollup/rollup-freebsd-x64": "4.37.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.37.0", + "@rollup/rollup-linux-arm-musleabihf": "4.37.0", + "@rollup/rollup-linux-arm64-gnu": "4.37.0", + "@rollup/rollup-linux-arm64-musl": "4.37.0", + "@rollup/rollup-linux-loongarch64-gnu": "4.37.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.37.0", + "@rollup/rollup-linux-riscv64-gnu": "4.37.0", + "@rollup/rollup-linux-riscv64-musl": "4.37.0", + "@rollup/rollup-linux-s390x-gnu": "4.37.0", + "@rollup/rollup-linux-x64-gnu": "4.37.0", + "@rollup/rollup-linux-x64-musl": "4.37.0", + "@rollup/rollup-win32-arm64-msvc": "4.37.0", + "@rollup/rollup-win32-ia32-msvc": "4.37.0", + "@rollup/rollup-win32-x64-msvc": "4.37.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup/node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "resolve.exports": { + "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" + } + ], + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", - "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", - "dev": true + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "ret": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.2.2.tgz", - "integrity": "sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==", - "dev": true + "node_modules/safe-regex2": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-3.1.0.tgz", + "integrity": "sha512-RAAZAGbap2kBfbVhvmnTFv73NWLMvDGOITFYTZBAaY8eR+Ir4ef7Up/e7amo+y1+AH+3PtLkrt9mvcTsG9LXug==", + "license": "MIT", + "dependencies": { + "ret": "~0.4.0" + } }, - "retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=" + "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" + } + }, + "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", + "optional": true + }, + "node_modules/secure-json-parse": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz", + "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==", + "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==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "license": "ISC" }, - "rfdc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", - "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", - "dev": true + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "license": "MIT" }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "requires": { - "glob": "^7.1.3" + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" } }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "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==", "dev": true, - "requires": { - "queue-microtask": "^1.2.2" + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" } }, - "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==" + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } }, - "safe-regex2": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-2.0.0.tgz", - "integrity": "sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ==", + "node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", "dev": true, - "requires": { - "ret": "~0.2.0" + "license": "MIT", + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "safe-stable-stringify": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.3.1.tgz", - "integrity": "sha512-kYBSfT+troD9cDA85VDnHZ1rpHC50O0g1e6WlGHVCz/g+JS+9WKLj+XwFYyR8UbrZN8ll9HUpDAAddY58MGisg==" + "node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "node_modules/shell-quote": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", + "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "sax": { + "node_modules/shimmer": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", - "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" + "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", + "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==", + "license": "BSD-2-Clause" }, - "saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "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==", "dev": true, - "requires": { - "xmlchars": "^2.2.0" + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "secure-json-parse": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.4.0.tgz", - "integrity": "sha512-Q5Z/97nbON5t/L/sH6mY2EacfjVGwrCcSi5D3btRO2GZ8pf1K1UN7Z9H5J57hjVU2Qzxr1xO+FmBhOvEkzCMmg==", - "dev": true - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "requires": { - "lru-cache": "^6.0.0" - } - }, - "semver-store": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/semver-store/-/semver-store-0.3.0.tgz", - "integrity": "sha512-TcZvGMMy9vodEFSse30lWinkj+JgOBvPn8wRItpQRSayhc+4ssDs335uklkfvQQJgL/WvmHLVj4Ycv2s7QCQMg==", - "dev": true - }, - "send": { - "version": "0.17.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", - "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", - "dev": true, - "requires": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "1.8.1", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - } + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" - }, - "set-cookie-parser": { - "version": "2.4.8", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.4.8.tgz", - "integrity": "sha512-edRH8mBKEWNVIVMKejNnuJxleqYE/ZSdcT8/Nem9/mmosx12pctd80s2Oy00KNZzrogMZS5mauK2/ymL1bvlvg==", - "dev": true - }, - "setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "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==", "dev": true, - "requires": { - "shebang-regex": "^3.0.0" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "shell-quote": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", - "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==", - "dev": true - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "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==", "dev": true, - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "signal-exit": { + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" - }, - "simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "dev": true + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" }, - "simple-get": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", - "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", "dev": true, - "requires": { - "decompress-response": "^4.2.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" } }, - "sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "slash": { + "node_modules/slash": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "smart-buffer": { + "node_modules/smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==" - }, - "socks": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz", - "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==", - "requires": { - "ip": "^1.1.5", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.4.tgz", + "integrity": "sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==", + "license": "MIT", + "dependencies": { + "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" } }, - "socks-proxy-agent": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.1.1.tgz", - "integrity": "sha512-t8J0kG3csjA4g6FTbsMOWws+7R7vuRC8aQ/wy3/1OWmsgwA68zs/+cExQ0koSitUDXqhufF/YJr9wtNMZHw5Ew==", - "requires": { + "node_modules/socks-proxy-agent": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", + "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", + "license": "MIT", + "dependencies": { "agent-base": "^6.0.2", - "debug": "^4.3.1", - "socks": "^2.6.1" + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" } }, - "sonic-boom": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-2.6.0.tgz", - "integrity": "sha512-6xYZFRmDEtxGqfOKcDQ4cPLrNa0SPEDI+wlzDAHowXE6YV42NeXqg9mP2KkiM8JVu3lHfZ2iQKYlGOz+kTpphg==", - "requires": { + "node_modules/sonic-boom": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.0.tgz", + "integrity": "sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==", + "license": "MIT", + "dependencies": { "atomic-sleep": "^1.0.0" } }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "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, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" } }, - "spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", "dev": true, - "requires": { + "license": "Apache-2.0", + "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" } }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" }, - "spdx-expression-parse": { + "node_modules/spdx-expression-parse": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, - "spdx-license-ids": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz", - "integrity": "sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==", - "dev": true + "node_modules/spdx-license-ids": { + "version": "3.0.21", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz", + "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==", + "dev": true, + "license": "CC0-1.0" }, - "split2": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", - "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", - "requires": { - "readable-stream": "^3.0.0" + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" } }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "sql-formatter": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/sql-formatter/-/sql-formatter-4.0.2.tgz", - "integrity": "sha512-R6u9GJRiXZLr/lDo8p56L+OyyN2QFJPCDnsyEOsbdIpsnDKL8gubYFo7lNR7Zx7hfdWT80SfkoVS0CMaF/DE2w==", - "requires": { - "argparse": "^2.0.1" + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "license": "BSD-3-Clause" + }, + "node_modules/sql-formatter": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/sql-formatter/-/sql-formatter-14.0.0.tgz", + "integrity": "sha512-VcHYMRvZqg3RNjjxNB/puT9O1hR5QLXTvgTaBtxXcvmRQwSnH9M+oW2Ti+uFuVVU8HoNlOjU2uKHv8c0FQNsdQ==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "get-stdin": "=8.0.0", + "nearley": "^2.20.1" + }, + "bin": { + "sql-formatter": "bin/sql-formatter-cli.cjs" } }, - "ssri": { + "node_modules/ssri": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", - "requires": { + "license": "ISC", + "dependencies": { "minipass": "^3.1.1" + }, + "engines": { + "node": ">= 8" } }, - "stack-utils": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", - "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", "dev": true, - "requires": { - "escape-string-regexp": "^2.0.0" - } + "license": "MIT" }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "dev": true + "node_modules/std-env": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.8.1.tgz", + "integrity": "sha512-vj5lIj3Mwf9D79hBkltk5qmkFI+biIKWS2IBxEyEU3AX1tUf7AoL8nSazCOiiqQsGKIq01SClsKEzweu34uwvA==", + "dev": true, + "license": "MIT" }, - "stream-meter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/stream-meter/-/stream-meter-1.0.4.tgz", - "integrity": "sha1-Uq+Vql6nYKJJFxZwTb/5D3Ov3R0=", - "dev": true, - "requires": { - "readable-stream": "^2.1.4" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "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" - } - }, - "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==", - "dev": true - }, - "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==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.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==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" } }, - "stream-shift": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" - }, - "string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "requires": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.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", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" } }, - "string-similarity": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/string-similarity/-/string-similarity-4.0.4.tgz", - "integrity": "sha512-/q/8Q4Bl4ZKAPjj8WerIBJWALKkaPRfrvhfF8k/B23i4nzrlRj2/go1m90In7nG/3XDSbOo0+pu6RvCTM9RGMQ==", - "dev": true - }, - "string-width": { + "node_modules/string-width-cjs": { + "name": "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==", - "requires": { + "dev": true, + "license": "MIT", + "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" } }, - "string.prototype.padend": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.3.tgz", - "integrity": "sha512-jNIIeokznm8SD/TZISQsZKYu7RJyheFNt84DUPrh482GC8RVp2MKqm2O5oBRdGxbDQoXrhhWtPIWQOiy20svUg==", + "node_modules/string.prototype.padend": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.6.tgz", + "integrity": "sha512-XZpspuSB7vJWhvJc9DLSlrXl1mcA2BdoY5jjnS135ydXqLoqhs96JjDtCkjJEQHvfqZIp9hBuBMgI589peyx9Q==", "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "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==", "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "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==", "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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==", - "requires": { - "safe-buffer": "~5.2.0" + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "strip-ansi": { + "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "requires": { + "license": "MIT", + "dependencies": { "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, - "strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true - }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } }, - "strip-indent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.0.0.tgz", - "integrity": "sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==", + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, - "requires": { - "min-indent": "^1.0.1" + "license": "MIT", + "engines": { + "node": ">=4" } }, - "strip-json-comments": { + "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "supports-color": { + "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "supports-hyperlinks": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", - "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", - "dev": true, - "requires": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, - "tar": { - "version": "6.1.11", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", - "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", - "requires": { + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "license": "ISC", + "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", - "minipass": "^3.0.0", + "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "license": "ISC", + "engines": { + "node": ">=8" + } + }, + "node_modules/tdigest": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.2.tgz", + "integrity": "sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA==", + "license": "MIT", + "dependencies": { + "bintrees": "1.0.2" + } + }, + "node_modules/test-exclude": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", + "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^10.4.1", + "minimatch": "^9.0.4" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/test-exclude/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/test-exclude/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/thread-stream": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-3.1.0.tgz", + "integrity": "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==", + "license": "MIT", + "dependencies": { + "real-require": "^0.2.0" + } + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz", + "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" } }, - "tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.4.4", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", + "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", "dev": true, - "requires": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" }, - "dependencies": { - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true + "peerDependenciesMeta": { + "picomatch": { + "optional": true } } }, - "tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, - "requires": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "node_modules/tinypool": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.2.tgz", + "integrity": "sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==", "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" } }, - "test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "node_modules/tinyrainbow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", "dev": true, - "requires": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" + "license": "MIT", + "engines": { + "node": ">=14.0.0" } }, - "thread-stream": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-0.13.0.tgz", - "integrity": "sha512-kTMZeX4Dzlb1zZ00/01aerGaTw2i8NE4sWF0TvF1uXewRhCiUjCvatQkvxIvFqauWG2ADFS2Wpd3qBeYL9i3dg==", - "requires": { - "real-require": "^0.1.0" + "node_modules/tinyspy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", + "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" } }, - "throat": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", - "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", - "dev": true - }, - "tiny-lru": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-8.0.2.tgz", - "integrity": "sha512-ApGvZ6vVvTNdsmt676grvCkUCGwzG9IqXma5Z07xJgiC5L7akUMof5U8G2JTI9Rz/ovtVhJBlY6mNhEvtjzOIg==", - "dev": true - }, - "tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - }, - "to-regex-range": { + "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" } }, - "toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true - }, - "tough-cookie": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", - "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", - "dev": true, - "requires": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.1.2" + "node_modules/toad-cache": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/toad-cache/-/toad-cache-3.7.0.tgz", + "integrity": "sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==", + "license": "MIT", + "engines": { + "node": ">=12" } }, - "tr46": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", - "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", "dev": true, - "requires": { - "punycode": "^2.1.1" + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" } }, - "tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "dev": true + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" }, - "trim-newlines": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-4.0.2.tgz", - "integrity": "sha512-GJtWyq9InR/2HRiLZgpIKv+ufIKrVrvjQWEj7PxAXNc5dwbNJkqhAUoAGgzRmULAnoOM5EIpveYd3J2VeSAIew==", - "dev": true - }, - "ts-jest": { - "version": "27.1.3", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.3.tgz", - "integrity": "sha512-6Nlura7s6uM9BVUAoqLH7JHyMXjz8gluryjpPXxr3IxZdAXnU6FhjvVLHFtfd1vsE1p8zD1OJfskkc0jhTSnkA==", - "dev": true, - "requires": { - "bs-logger": "0.x", - "fast-json-stable-stringify": "2.x", - "jest-util": "^27.0.0", - "json5": "2.x", - "lodash.memoize": "4.x", - "make-error": "1.x", - "semver": "7.x", - "yargs-parser": "20.x" - } - }, - "ts-node": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz", - "integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==", - "dev": true, - "requires": { + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", "arg": "^4.1.0", "create-require": "^1.1.0", "diff": "^4.0.1", "make-error": "^1.1.1", - "source-map-support": "^0.5.17", + "v8-compile-cache-lib": "^3.0.1", "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } } }, - "ts-node-dev": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/ts-node-dev/-/ts-node-dev-1.1.8.tgz", - "integrity": "sha512-Q/m3vEwzYwLZKmV6/0VlFxcZzVV/xcgOt+Tx/VjaaRHyiBcFlV0541yrT09QjzzCxlDZ34OzKjrFAynlmtflEg==", + "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/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==", "dev": true, - "requires": { - "chokidar": "^3.5.1", - "dynamic-dedupe": "^0.3.0", - "minimist": "^1.2.5", - "mkdirp": "^1.0.4", - "resolve": "^1.0.0", - "rimraf": "^2.6.1", - "source-map-support": "^0.5.12", - "tree-kill": "^1.2.2", - "ts-node": "^9.0.0", - "tsconfig": "^7.0.0" - }, - "dependencies": { - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" } }, - "tsconfig": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz", - "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==", + "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==", "dev": true, - "requires": { - "@types/strip-bom": "^3.0.0", - "@types/strip-json-comments": "0.0.30", - "strip-bom": "^3.0.0", - "strip-json-comments": "^2.0.0" - }, + "license": "MIT", "dependencies": { - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true - } + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "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==", "dev": true, - "requires": { - "safe-buffer": "^5.0.1" + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "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==", "dev": true, - "requires": { - "prelude-ls": "~1.1.2" + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true - }, - "type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true - }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "node_modules/typescript": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", + "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", "dev": true, - "requires": { - "is-typedarray": "^1.0.0" + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" } }, - "typescript": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.2.tgz", - "integrity": "sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg==", - "dev": true - }, - "unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "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==", "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "unique-filename": { + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "license": "MIT" + }, + "node_modules/unique-filename": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", - "requires": { + "license": "ISC", + "dependencies": { "unique-slug": "^2.0.0" } }, - "unique-slug": { + "node_modules/unique-slug": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", - "requires": { + "license": "ISC", + "dependencies": { "imurmurhash": "^0.1.4" } }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true - }, - "uri-js": { + "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "url": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", - "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - }, + "license": "BSD-2-Clause", "dependencies": { - "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" - } + "punycode": "^2.1.0" } }, - "util-deprecate": { + "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" }, - "v8-to-istanbul": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.0.tgz", - "integrity": "sha512-/PRhfd8aTNp9Ggr62HPzXg2XasNFGy5PBt0Rp04du7/8GNNSgxFL6WBTkgMKSL9bFjH+8kKEG3f37FmxiTqUUA==", + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0", - "source-map": "^0.7.3" - }, - "dependencies": { - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true - } - } + "license": "MIT" }, - "validate-npm-package-license": { + "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, - "requires": { + "license": "Apache-2.0", + "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "dev": true - }, - "w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "node_modules/vite": { + "version": "6.3.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.4.tgz", + "integrity": "sha512-BiReIiMS2fyFqbqNT/Qqt4CVITDU9M9vE+DKcVAsB+ZV0wvTKd+3hMbkpxz1b+NmEDMegpVbisKiAZOnvO92Sw==", "dev": true, - "requires": { - "browser-process-hrtime": "^1.0.0" + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } } }, - "w3c-xmlserializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "node_modules/vite-node": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.9.tgz", + "integrity": "sha512-w3Gdx7jDcuT9cNn9jExXgOyKmf5UOTb6WMHz8LGAm54eS1Elf5OuBhCxl6zJxGhEeIkgsE1WbHuoL0mj/UXqXg==", "dev": true, - "requires": { - "xml-name-validator": "^3.0.0" + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.4.0", + "es-module-lexer": "^1.6.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.0.0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "wait-for-localhost": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/wait-for-localhost/-/wait-for-localhost-4.0.0.tgz", - "integrity": "sha512-XkP+FzzqJC1zVaB5xK4Z9/IErtszPsns232opPlMaskmBHVudmpSZxv8cTtw6FkXCk78Vw0236Prv35YOwGvfg==", - "dev": true + "node_modules/vite/node_modules/fdir": { + "version": "6.4.4", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", + "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } }, - "wait-for-localhost-cli": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/wait-for-localhost-cli/-/wait-for-localhost-cli-3.0.0.tgz", - "integrity": "sha512-M7oS3qIIeX11Fo5G+z5IX6uS/w03uC6HtM6beHkQ2xh9MSYgJOKdTC6Z488HJ5DAAqdwUaW1x50Inz8KXY1GTQ==", + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, - "requires": { - "meow": "^10.1.1", - "wait-for-localhost": "^4.0.0" + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "node_modules/vitest": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.0.9.tgz", + "integrity": "sha512-BbcFDqNyBlfSpATmTtXOAOj71RNKDDvjBM/uPfnxxVGrG+FSH2RQIwgeEngTaTkuU/h0ScFvf+tRcKfYXzBybQ==", "dev": true, - "requires": { - "makeerror": "1.0.12" + "license": "MIT", + "dependencies": { + "@vitest/expect": "3.0.9", + "@vitest/mocker": "3.0.9", + "@vitest/pretty-format": "^3.0.9", + "@vitest/runner": "3.0.9", + "@vitest/snapshot": "3.0.9", + "@vitest/spy": "3.0.9", + "@vitest/utils": "3.0.9", + "chai": "^5.2.0", + "debug": "^4.4.0", + "expect-type": "^1.1.0", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "std-env": "^3.8.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinypool": "^1.0.2", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0", + "vite-node": "3.0.9", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.0.9", + "@vitest/ui": "3.0.9", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } } }, - "webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", - "dev": true + "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" }, - "whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "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", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, - "requires": { - "iconv-lite": "0.4.24" + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" }, + "bin": { + "which": "bin/which" + } + }, + "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==", + "dev": true, + "license": "MIT", "dependencies": { - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - } + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "whatwg-url": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", - "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "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==", "dev": true, - "requires": { - "lodash": "^4.7.0", - "tr46": "^2.1.0", - "webidl-conversions": "^6.1.0" + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "requires": { - "isexe": "^2.0.0" + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", "dev": true, - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" } }, - "wide-align": { + "node_modules/wide-align": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "requires": { + "license": "ISC", + "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" } }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } }, - "wrap-ansi": { + "node_modules/wrap-ansi-cjs": { + "name": "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==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } }, - "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "node_modules/wrap-ansi-cjs/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi-cjs/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==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "ws": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.6.tgz", - "integrity": "sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==", - "dev": true + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } }, - "xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" }, - "xml2js": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", - "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~9.0.1" + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "xmlbuilder": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", - "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=" + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } }, - "xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true + "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" }, - "xtend": { + "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } }, - "yallist": { + "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "requires": { - "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" - } - }, - "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==", - "dev": true - }, - "yn": { + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, + "node_modules/yaml": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz", + "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } } } } diff --git a/package.json b/package.json index b7108b0d..62315e9f 100644 --- a/package.json +++ b/package.json @@ -9,62 +9,68 @@ "files": [ "dist" ], - "main": "dist/main/index.js", - "module": "dist/module/index.js", + "type": "module", + "main": "dist/lib/index.js", + "types": "dist/lib/index.d.ts", + "imports": { + "#package.json": "./package.json" + }, "repository": "supabase/postgres-meta", "scripts": { - "clean": "rimraf bin dist", - "format": "prettier --write \"{src,test}/**/*.ts\"", - "build": "run-s clean build:*", - "build:main": "tsc -p tsconfig.json && cpy 'src/lib/sql/*.sql' dist/main/sql", - "build:module": "tsc -p tsconfig.module.json && cpy 'src/lib/sql/*.sql' dist/module/sql", - "build:server": "tsc -p tsconfig.server.json && cpy 'src/lib/sql/*.sql' bin/src/lib/sql", - "docs:export": "PG_META_EXPORT_DOCS=true ts-node-dev src/server/app.ts", - "start": "NODE_ENV=production node bin/src/server/app.js", - "dev": "trap 'npm run db:clean' INT && run-s db:clean db:run && NODE_ENV=development ts-node-dev src/server/app.ts | pino-pretty --colorize", - "pkg": "run-s clean build:server && pkg --out-path bin .pkg.config.json", + "check": "tsc -p tsconfig.json --noEmit", + "clean": "rimraf dist tsconfig.tsbuildinfo", + "format": "prettier --write '{src,test}/**/*.ts' '*.ts'", + "build": "tsc -p tsconfig.json && cpy 'src/lib/sql/*.sql' dist/lib/sql", + "docs:export": "PG_META_EXPORT_DOCS=true node --loader ts-node/esm src/server/server.ts > openapi.json", + "gen:types:typescript": "PG_META_GENERATE_TYPES=typescript node --loader ts-node/esm src/server/server.ts", + "gen:types:go": "PG_META_GENERATE_TYPES=go node --loader ts-node/esm src/server/server.ts", + "gen:types:swift": "PG_META_GENERATE_TYPES=swift node --loader ts-node/esm src/server/server.ts", + "start": "node dist/server/server.js", + "dev": "trap 'npm run db:clean' INT && run-s db:clean db:run && nodemon --exec node --loader ts-node/esm src/server/server.ts | pino-pretty --colorize", "test": "run-s db:clean db:run test:run db:clean", - "db:clean": "cd test/db && docker-compose down", - "db:run": "cd test/db && docker-compose up --detach && sleep 5", - "test:run": "jest --runInBand", - "test:update": "run-s db:clean db:run && jest --runInBand --updateSnapshot && run-s db:clean" + "db:clean": "cd test/db && docker compose down", + "db:run": "cd test/db && docker compose up --detach --wait", + "test:run": "PG_META_MAX_RESULT_SIZE_MB=20 PG_QUERY_TIMEOUT_SECS=5 PG_CONN_TIMEOUT_SECS=30 vitest run --coverage", + "test:update": "run-s db:clean db:run && PG_META_MAX_RESULT_SIZE_MB=20 PG_QUERY_TIMEOUT_SECS=5 PG_CONN_TIMEOUT_SECS=30 vitest run --update && run-s db:clean" }, "engines": { - "node": ">=14 <15", - "npm": ">=7" + "node": ">=20", + "npm": ">=9" }, "dependencies": { - "@sinclair/typebox": "^0.23.4", - "pg": "^8.7.1", + "@fastify/cors": "^9.0.1", + "@fastify/swagger": "^8.2.1", + "@fastify/type-provider-typebox": "^3.5.0", + "@sentry/node": "^9.12.0", + "@sentry/profiling-node": "^9.12.0", + "@sinclair/typebox": "^0.31.25", + "close-with-grace": "^2.1.0", + "crypto-js": "^4.0.0", + "fastify": "^4.24.3", + "fastify-metrics": "^10.0.0", + "pg": "npm:@supabase/pg@0.0.3", + "pg-connection-string": "^2.7.0", "pg-format": "^1.0.4", - "pgsql-parser": "^13.3.0", - "pino": "^7.6.3", + "pg-protocol": "npm:@supabase/pg-protocol@0.0.2", + "pgsql-parser": "^13.16.0", + "pino": "^9.5.0", "postgres-array": "^3.0.1", - "prettier": "^2.6.0", - "prettier-plugin-sql": "^0.4.0", - "sql-formatter": "^4.0.2" + "prettier": "^3.3.3", + "prettier-plugin-sql": "0.17.1" }, "devDependencies": { "@types/crypto-js": "^4.1.1", - "@types/jest": "^27.0.1", - "@types/node": "^17.0.21", - "@types/pg": "^8.6.5", + "@types/node": "^20.11.14", + "@types/pg": "^8.11.10", "@types/pg-format": "^1.0.1", - "@types/pino": "^7.0.5", - "cpy-cli": "^4.1.0", - "crypto-js": "^4.0.0", - "fastify": "^3.14.0", - "fastify-cors": "^6.0.3", - "fastify-swagger": "^5.0.0", - "jest": "^27.1.0", + "@vitest/coverage-v8": "^3.0.5", + "cpy-cli": "^5.0.0", + "nodemon": "^3.1.7", "npm-run-all": "^4.1.5", - "pg-connection-string": "^2.5.0", - "pino-pretty": "^7.5.4", - "pkg": "^5.5.2", - "rimraf": "^3.0.2", - "ts-jest": "^27.0.5", - "ts-node-dev": "^1.1.6", - "typescript": "^4.3.2", - "wait-for-localhost-cli": "^3.0.0" + "pino-pretty": "^12.0.0", + "rimraf": "^6.0.1", + "ts-node": "^10.9.1", + "typescript": "^5.6.3", + "vitest": "^3.0.5" } } diff --git a/src/lib/Parser.ts b/src/lib/Parser.ts index cff19034..abfc269d 100644 --- a/src/lib/Parser.ts +++ b/src/lib/Parser.ts @@ -1,14 +1,13 @@ -import { FormatterOptions } from './types' -const { parse, deparse } = require('pgsql-parser') -import prettier from 'prettier/standalone' +import prettier from 'prettier/standalone.js' import SqlFormatter from 'prettier-plugin-sql' +import { parse, deparse } from 'pgsql-parser' +import { FormatterOptions } from './types.js' const DEFAULT_FORMATTER_OPTIONS = { plugins: [SqlFormatter], formatter: 'sql-formatter', language: 'postgresql', database: 'postgresql', - uppercase: false, // I thought this would "lowercase" everything, but it doesn't. There is not option to convert everything to lowercase. parser: 'sql', } @@ -34,8 +33,7 @@ interface ParseReturnValues { */ export function Deparse(parsedSql: object): DeparseReturnValues { try { - const data = deparse(parsedSql) - + const data = deparse(parsedSql, {}) return { data, error: null } } catch (error) { return { data: null, error: error as Error } @@ -49,9 +47,12 @@ interface DeparseReturnValues { /** * Formats a SQL string into a prettier-formatted SQL string. */ -export function Format(sql: string, options: FormatterOptions = {}): FormatReturnValues { +export async function Format( + sql: string, + options: FormatterOptions = {} +): Promise { try { - const formatted = prettier.format(sql, { + const formatted = await prettier.format(sql, { ...DEFAULT_FORMATTER_OPTIONS, ...options, }) diff --git a/src/lib/PostgresMeta.ts b/src/lib/PostgresMeta.ts index 069cf21d..91050383 100644 --- a/src/lib/PostgresMeta.ts +++ b/src/lib/PostgresMeta.ts @@ -1,31 +1,46 @@ -import { PoolConfig } from 'pg' -import * as Parser from './Parser' -import PostgresMetaColumns from './PostgresMetaColumns' -import PostgresMetaConfig from './PostgresMetaConfig' -import PostgresMetaExtensions from './PostgresMetaExtensions' -import PostgresMetaFunctions from './PostgresMetaFunctions' -import PostgresMetaPolicies from './PostgresMetaPolicies' -import PostgresMetaPublications from './PostgresMetaPublications' -import PostgresMetaRoles from './PostgresMetaRoles' -import PostgresMetaSchemas from './PostgresMetaSchemas' -import PostgresMetaTables from './PostgresMetaTables' -import PostgresMetaTriggers from './PostgresMetaTriggers' -import PostgresMetaTypes from './PostgresMetaTypes' -import PostgresMetaVersion from './PostgresMetaVersion' -import PostgresMetaViews from './PostgresMetaViews' -import { init } from './db' -import { PostgresMetaResult } from './types' +import * as Parser from './Parser.js' +import PostgresMetaColumnPrivileges from './PostgresMetaColumnPrivileges.js' +import PostgresMetaColumns from './PostgresMetaColumns.js' +import PostgresMetaConfig from './PostgresMetaConfig.js' +import PostgresMetaExtensions from './PostgresMetaExtensions.js' +import PostgresMetaForeignTables from './PostgresMetaForeignTables.js' +import PostgresMetaFunctions from './PostgresMetaFunctions.js' +import PostgresMetaIndexes from './PostgresMetaIndexes.js' +import PostgresMetaMaterializedViews from './PostgresMetaMaterializedViews.js' +import PostgresMetaPolicies from './PostgresMetaPolicies.js' +import PostgresMetaPublications from './PostgresMetaPublications.js' +import PostgresMetaRelationships from './PostgresMetaRelationships.js' +import PostgresMetaRoles from './PostgresMetaRoles.js' +import PostgresMetaSchemas from './PostgresMetaSchemas.js' +import PostgresMetaTablePrivileges from './PostgresMetaTablePrivileges.js' +import PostgresMetaTables from './PostgresMetaTables.js' +import PostgresMetaTriggers from './PostgresMetaTriggers.js' +import PostgresMetaTypes from './PostgresMetaTypes.js' +import PostgresMetaVersion from './PostgresMetaVersion.js' +import PostgresMetaViews from './PostgresMetaViews.js' +import { init } from './db.js' +import { PostgresMetaResult, PoolConfig } from './types.js' + export default class PostgresMeta { - query: (sql: string) => Promise> + query: ( + sql: string, + opts?: { statementQueryTimeout?: number; trackQueryInSentry?: boolean } + ) => Promise> end: () => Promise + columnPrivileges: PostgresMetaColumnPrivileges columns: PostgresMetaColumns config: PostgresMetaConfig extensions: PostgresMetaExtensions + foreignTables: PostgresMetaForeignTables functions: PostgresMetaFunctions + indexes: PostgresMetaIndexes + materializedViews: PostgresMetaMaterializedViews policies: PostgresMetaPolicies publications: PostgresMetaPublications + relationships: PostgresMetaRelationships roles: PostgresMetaRoles schemas: PostgresMetaSchemas + tablePrivileges: PostgresMetaTablePrivileges tables: PostgresMetaTables triggers: PostgresMetaTriggers types: PostgresMetaTypes @@ -40,14 +55,20 @@ export default class PostgresMeta { const { query, end } = init(config) this.query = query this.end = end + this.columnPrivileges = new PostgresMetaColumnPrivileges(this.query) this.columns = new PostgresMetaColumns(this.query) this.config = new PostgresMetaConfig(this.query) this.extensions = new PostgresMetaExtensions(this.query) + this.foreignTables = new PostgresMetaForeignTables(this.query) this.functions = new PostgresMetaFunctions(this.query) + this.indexes = new PostgresMetaIndexes(this.query) + this.materializedViews = new PostgresMetaMaterializedViews(this.query) this.policies = new PostgresMetaPolicies(this.query) this.publications = new PostgresMetaPublications(this.query) + this.relationships = new PostgresMetaRelationships(this.query) this.roles = new PostgresMetaRoles(this.query) this.schemas = new PostgresMetaSchemas(this.query) + this.tablePrivileges = new PostgresMetaTablePrivileges(this.query) this.tables = new PostgresMetaTables(this.query) this.triggers = new PostgresMetaTriggers(this.query) this.types = new PostgresMetaTypes(this.query) diff --git a/src/lib/PostgresMetaColumnPrivileges.ts b/src/lib/PostgresMetaColumnPrivileges.ts new file mode 100644 index 00000000..4df0d39a --- /dev/null +++ b/src/lib/PostgresMetaColumnPrivileges.ts @@ -0,0 +1,141 @@ +import { ident, literal } from 'pg-format' +import { DEFAULT_SYSTEM_SCHEMAS } from './constants.js' +import { filterByList } from './helpers.js' +import { columnPrivilegesSql } from './sql/index.js' +import { + PostgresMetaResult, + PostgresColumnPrivileges, + PostgresColumnPrivilegesGrant, + PostgresColumnPrivilegesRevoke, +} from './types.js' + +export default class PostgresMetaColumnPrivileges { + query: (sql: string) => Promise> + + constructor(query: (sql: string) => Promise>) { + this.query = query + } + + async list({ + includeSystemSchemas = false, + includedSchemas, + excludedSchemas, + limit, + offset, + }: { + includeSystemSchemas?: boolean + includedSchemas?: string[] + excludedSchemas?: string[] + limit?: number + offset?: number + } = {}): Promise> { + let sql = ` +with column_privileges as (${columnPrivilegesSql}) +select * +from column_privileges +` + const filter = filterByList( + includedSchemas, + excludedSchemas, + !includeSystemSchemas ? DEFAULT_SYSTEM_SCHEMAS : undefined + ) + if (filter) { + sql += ` where relation_schema ${filter}` + } + if (limit) { + sql += ` limit ${limit}` + } + if (offset) { + sql += ` offset ${offset}` + } + return await this.query(sql) + } + + async grant( + grants: PostgresColumnPrivilegesGrant[] + ): Promise> { + let sql = ` +do $$ +declare + col record; +begin +${grants + .map(({ privilege_type, column_id, grantee, is_grantable }) => { + const [relationId, columnNumber] = column_id.split('.') + return ` +select * +from pg_attribute a +where a.attrelid = ${literal(relationId)} + and a.attnum = ${literal(columnNumber)} +into col; +execute format( + 'grant ${privilege_type} (%I) on %s to ${ + grantee.toLowerCase() === 'public' ? 'public' : ident(grantee) + } ${is_grantable ? 'with grant option' : ''}', + col.attname, + col.attrelid::regclass +);` + }) + .join('\n')} +end $$; +` + const { data, error } = await this.query(sql) + if (error) { + return { data, error } + } + + // Return the updated column privileges for modified columns. + const columnIds = [...new Set(grants.map(({ column_id }) => column_id))] + sql = ` +with column_privileges as (${columnPrivilegesSql}) +select * +from column_privileges +where column_id in (${columnIds.map(literal).join(',')}) +` + return await this.query(sql) + } + + async revoke( + revokes: PostgresColumnPrivilegesRevoke[] + ): Promise> { + let sql = ` +do $$ +declare + col record; +begin +${revokes + .map(({ privilege_type, column_id, grantee }) => { + const [relationId, columnNumber] = column_id.split('.') + return ` +select * +from pg_attribute a +where a.attrelid = ${literal(relationId)} + and a.attnum = ${literal(columnNumber)} +into col; +execute format( + 'revoke ${privilege_type} (%I) on %s from ${ + grantee.toLowerCase() === 'public' ? 'public' : ident(grantee) + }', + col.attname, + col.attrelid::regclass +);` + }) + .join('\n')} +end $$; +` + const { data, error } = await this.query(sql) + if (error) { + return { data, error } + } + + // Return the updated column privileges for modified columns. + const columnIds = [...new Set(revokes.map(({ column_id }) => column_id))] + sql = ` +with column_privileges as (${columnPrivilegesSql}) +select * +from column_privileges +where column_id in (${columnIds.map(literal).join(',')}) +` + return await this.query(sql) + } +} diff --git a/src/lib/PostgresMetaColumns.ts b/src/lib/PostgresMetaColumns.ts index 01897c06..15e56507 100644 --- a/src/lib/PostgresMetaColumns.ts +++ b/src/lib/PostgresMetaColumns.ts @@ -1,8 +1,9 @@ import { ident, literal } from 'pg-format' -import PostgresMetaTables from './PostgresMetaTables' -import { DEFAULT_SYSTEM_SCHEMAS } from './constants' -import { columnsSql } from './sql' -import { PostgresMetaResult, PostgresColumn } from './types' +import PostgresMetaTables from './PostgresMetaTables.js' +import { DEFAULT_SYSTEM_SCHEMAS } from './constants.js' +import { columnsSql } from './sql/index.js' +import { PostgresMetaResult, PostgresColumn } from './types.js' +import { filterByList } from './helpers.js' export default class PostgresMetaColumns { query: (sql: string) => Promise> @@ -14,23 +15,45 @@ export default class PostgresMetaColumns { } async list({ + tableId, includeSystemSchemas = false, + includedSchemas, + excludedSchemas, limit, offset, }: { + tableId?: number includeSystemSchemas?: boolean + includedSchemas?: string[] + excludedSchemas?: string[] limit?: number offset?: number } = {}): Promise> { - let sql = columnsSql - if (!includeSystemSchemas) { - sql = `${sql} AND NOT (nc.nspname IN (${DEFAULT_SYSTEM_SCHEMAS.map(literal).join(',')}))` + let sql = ` +WITH + columns AS (${columnsSql}) +SELECT + * +FROM + columns +WHERE + true` + const filter = filterByList( + includedSchemas, + excludedSchemas, + !includeSystemSchemas ? DEFAULT_SYSTEM_SCHEMAS : undefined + ) + if (filter) { + sql += ` AND schema ${filter}` + } + if (tableId !== undefined) { + sql += ` AND table_id = ${literal(tableId)}` } if (limit) { - sql = `${sql} LIMIT ${limit}` + sql += ` LIMIT ${limit}` } if (offset) { - sql = `${sql} OFFSET ${offset}` + sql += ` OFFSET ${offset}` } return await this.query(sql) } @@ -190,6 +213,7 @@ COMMIT;` is_nullable, is_unique, comment, + check, }: { name?: string type?: string @@ -201,6 +225,7 @@ COMMIT;` is_nullable?: boolean is_unique?: boolean comment?: string + check?: string | null } ): Promise> { const { data: old, error } = await this.retrieve({ id }) @@ -305,6 +330,52 @@ $$; old!.name )} IS ${literal(comment)};` + const checkSql = + check === undefined + ? '' + : ` +DO $$ +DECLARE + v_conname name; + v_conkey int2[]; +BEGIN + SELECT conname into v_conname FROM pg_constraint WHERE + contype = 'c' + AND cardinality(conkey) = 1 + AND conrelid = ${literal(old!.table_id)} + AND conkey[1] = ${literal(old!.ordinal_position)} + ORDER BY oid asc + LIMIT 1; + + IF v_conname IS NOT NULL THEN + EXECUTE format('ALTER TABLE ${ident(old!.schema)}.${ident( + old!.table + )} DROP CONSTRAINT %s', v_conname); + END IF; + + ${ + check !== null + ? ` + ALTER TABLE ${ident(old!.schema)}.${ident(old!.table)} ADD CONSTRAINT ${ident( + `${old!.table}_${old!.name}_check` + )} CHECK (${check}); + + SELECT conkey into v_conkey FROM pg_constraint WHERE conname = ${literal( + `${old!.table}_${old!.name}_check` + )}; + + ASSERT v_conkey IS NOT NULL, 'error creating column constraint: check condition must refer to this column'; + ASSERT cardinality(v_conkey) = 1, 'error creating column constraint: check condition cannot refer to multiple columns'; + ASSERT v_conkey[1] = ${literal( + old!.ordinal_position + )}, 'error creating column constraint: check condition cannot refer to other columns'; + ` + : '' + } +END +$$; +` + // TODO: Can't set default if column is previously identity even if // is_identity: false. Must do two separate PATCHes (once to drop identity // and another to set default). @@ -318,6 +389,7 @@ BEGIN; ${identitySql} ${isUniqueSql} ${commentSql} + ${checkSql} ${nameSql} COMMIT;` { @@ -329,14 +401,14 @@ COMMIT;` return await this.retrieve({ id }) } - async remove(id: string): Promise> { + async remove(id: string, { cascade = false } = {}): Promise> { const { data: column, error } = await this.retrieve({ id }) if (error) { return { data: null, error } } const sql = `ALTER TABLE ${ident(column!.schema)}.${ident(column!.table)} DROP COLUMN ${ident( column!.name - )};` + )} ${cascade ? 'CASCADE' : 'RESTRICT'};` { const { error } = await this.query(sql) if (error) { @@ -347,6 +419,12 @@ COMMIT;` } } +// TODO: make this more robust - use type_id or type_schema + type_name instead +// of just type. const typeIdent = (type: string) => { - return type.endsWith('[]') ? `${ident(type.slice(0, -2))}[]` : ident(type) + return type.endsWith('[]') + ? `${ident(type.slice(0, -2))}[]` + : type.includes('.') + ? type + : ident(type) } diff --git a/src/lib/PostgresMetaConfig.ts b/src/lib/PostgresMetaConfig.ts index 1e1c7673..d362641b 100644 --- a/src/lib/PostgresMetaConfig.ts +++ b/src/lib/PostgresMetaConfig.ts @@ -1,5 +1,5 @@ -import { configSql } from './sql' -import { PostgresMetaResult, PostgresConfig } from './types' +import { configSql } from './sql/index.js' +import { PostgresMetaResult, PostgresConfig } from './types.js' export default class PostgresMetaConfig { query: (sql: string) => Promise> diff --git a/src/lib/PostgresMetaExtensions.ts b/src/lib/PostgresMetaExtensions.ts index a923c19c..4589057f 100644 --- a/src/lib/PostgresMetaExtensions.ts +++ b/src/lib/PostgresMetaExtensions.ts @@ -1,6 +1,6 @@ import { ident, literal } from 'pg-format' -import { extensionsSql } from './sql' -import { PostgresMetaResult, PostgresExtension } from './types' +import { extensionsSql } from './sql/index.js' +import { PostgresMetaResult, PostgresExtension } from './types.js' export default class PostgresMetaExtensions { query: (sql: string) => Promise> diff --git a/src/lib/PostgresMetaForeignTables.ts b/src/lib/PostgresMetaForeignTables.ts new file mode 100644 index 00000000..40ed859f --- /dev/null +++ b/src/lib/PostgresMetaForeignTables.ts @@ -0,0 +1,116 @@ +import { literal } from 'pg-format' +import { coalesceRowsToArray, filterByList } from './helpers.js' +import { columnsSql, foreignTablesSql } from './sql/index.js' +import { PostgresMetaResult, PostgresForeignTable } from './types.js' + +export default class PostgresMetaForeignTables { + query: (sql: string) => Promise> + + constructor(query: (sql: string) => Promise>) { + this.query = query + } + + async list(options: { + includedSchemas?: string[] + excludedSchemas?: string[] + limit?: number + offset?: number + includeColumns: false + }): Promise> + async list(options?: { + includedSchemas?: string[] + excludedSchemas?: string[] + limit?: number + offset?: number + includeColumns?: boolean + }): Promise> + async list({ + includedSchemas, + excludedSchemas, + limit, + offset, + includeColumns = true, + }: { + includedSchemas?: string[] + excludedSchemas?: string[] + limit?: number + offset?: number + includeColumns?: boolean + } = {}): Promise> { + let sql = generateEnrichedForeignTablesSql({ includeColumns }) + const filter = filterByList(includedSchemas, excludedSchemas) + if (filter) { + sql += ` where schema ${filter}` + } + if (limit) { + sql += ` limit ${limit}` + } + if (offset) { + sql += ` offset ${offset}` + } + return await this.query(sql) + } + + async retrieve({ id }: { id: number }): Promise> + async retrieve({ + name, + schema, + }: { + name: string + schema: string + }): Promise> + async retrieve({ + id, + name, + schema = 'public', + }: { + id?: number + name?: string + schema?: string + }): Promise> { + if (id) { + const sql = `${generateEnrichedForeignTablesSql({ + includeColumns: true, + })} where foreign_tables.id = ${literal(id)};` + const { data, error } = await this.query(sql) + if (error) { + return { data, error } + } else if (data.length === 0) { + return { data: null, error: { message: `Cannot find a foreign table with ID ${id}` } } + } else { + return { data: data[0], error } + } + } else if (name) { + const sql = `${generateEnrichedForeignTablesSql({ + includeColumns: true, + })} where foreign_tables.name = ${literal(name)} and foreign_tables.schema = ${literal( + schema + )};` + const { data, error } = await this.query(sql) + if (error) { + return { data, error } + } else if (data.length === 0) { + return { + data: null, + error: { message: `Cannot find a foreign table named ${name} in schema ${schema}` }, + } + } else { + return { data: data[0], error } + } + } else { + return { data: null, error: { message: 'Invalid parameters on foreign table retrieve' } } + } + } +} + +const generateEnrichedForeignTablesSql = ({ includeColumns }: { includeColumns: boolean }) => ` +with foreign_tables as (${foreignTablesSql}) + ${includeColumns ? `, columns as (${columnsSql})` : ''} +select + * + ${ + includeColumns + ? `, ${coalesceRowsToArray('columns', 'columns.table_id = foreign_tables.id')}` + : '' + } +from foreign_tables` diff --git a/src/lib/PostgresMetaFunctions.ts b/src/lib/PostgresMetaFunctions.ts index df320626..b50e6761 100644 --- a/src/lib/PostgresMetaFunctions.ts +++ b/src/lib/PostgresMetaFunctions.ts @@ -1,7 +1,8 @@ import { ident, literal } from 'pg-format' -import { DEFAULT_SYSTEM_SCHEMAS } from './constants' -import { functionsSql } from './sql' -import { PostgresMetaResult, PostgresFunction, PostgresFunctionCreate } from './types' +import { DEFAULT_SYSTEM_SCHEMAS } from './constants.js' +import { filterByList } from './helpers.js' +import { functionsSql } from './sql/index.js' +import { PostgresMetaResult, PostgresFunction, PostgresFunctionCreate } from './types.js' export default class PostgresMetaFunctions { query: (sql: string) => Promise> @@ -12,16 +13,25 @@ export default class PostgresMetaFunctions { async list({ includeSystemSchemas = false, + includedSchemas, + excludedSchemas, limit, offset, }: { includeSystemSchemas?: boolean + includedSchemas?: string[] + excludedSchemas?: string[] limit?: number offset?: number } = {}): Promise> { let sql = enrichedFunctionsSql - if (!includeSystemSchemas) { - sql = `${sql} WHERE NOT (schema IN (${DEFAULT_SYSTEM_SCHEMAS.map(literal).join(',')}))` + const filter = filterByList( + includedSchemas, + excludedSchemas, + !includeSystemSchemas ? DEFAULT_SYSTEM_SCHEMAS : undefined + ) + if (filter) { + sql += ` WHERE schema ${filter}` } if (limit) { sql = `${sql} LIMIT ${limit}` @@ -173,8 +183,8 @@ export default class PostgresMetaFunctions { AND f.identity_argument_types = ${literal(identityArgs)} ) != ${id} THEN RAISE EXCEPTION 'Cannot find function "${currentFunc!.schema}"."${ - currentFunc!.name - }"(${identityArgs})'; + currentFunc!.name + }"(${identityArgs})'; END IF; END IF; @@ -232,8 +242,8 @@ export default class PostgresMetaFunctions { ): string { return ` CREATE ${replace ? 'OR REPLACE' : ''} FUNCTION ${ident(schema!)}.${ident(name!)}(${ - args?.join(', ') || '' - }) + args?.join(', ') || '' + }) RETURNS ${return_type} AS ${literal(definition)} LANGUAGE ${language} diff --git a/src/lib/PostgresMetaIndexes.ts b/src/lib/PostgresMetaIndexes.ts new file mode 100644 index 00000000..14ffbba7 --- /dev/null +++ b/src/lib/PostgresMetaIndexes.ts @@ -0,0 +1,85 @@ +import { ident, literal } from 'pg-format' +import { DEFAULT_SYSTEM_SCHEMAS } from './constants.js' +import { filterByList } from './helpers.js' +import { indexesSql } from './sql/index.js' +import { PostgresMetaResult, PostgresIndex } from './types.js' + +export default class PostgresMetaFunctions { + query: (sql: string) => Promise> + + constructor(query: (sql: string) => Promise>) { + this.query = query + } + + async list({ + includeSystemSchemas = false, + includedSchemas, + excludedSchemas, + limit, + offset, + }: { + includeSystemSchemas?: boolean + includedSchemas?: string[] + excludedSchemas?: string[] + limit?: number + offset?: number + } = {}): Promise> { + let sql = enrichedSql + const filter = filterByList( + includedSchemas, + excludedSchemas, + !includeSystemSchemas ? DEFAULT_SYSTEM_SCHEMAS : undefined + ) + if (filter) { + sql += ` WHERE schema ${filter}` + } + if (limit) { + sql = `${sql} LIMIT ${limit}` + } + if (offset) { + sql = `${sql} OFFSET ${offset}` + } + return await this.query(sql) + } + + async retrieve({ id }: { id: number }): Promise> + async retrieve({ + name, + schema, + args, + }: { + name: string + schema: string + args: string[] + }): Promise> + async retrieve({ + id, + args = [], + }: { + id?: number + args?: string[] + }): Promise> { + if (id) { + const sql = `${enrichedSql} WHERE id = ${literal(id)};` + const { data, error } = await this.query(sql) + if (error) { + return { data, error } + } else if (data.length === 0) { + return { data: null, error: { message: `Cannot find a index with ID ${id}` } } + } else { + return { data: data[0], error } + } + } else { + return { data: null, error: { message: 'Invalid parameters on function retrieve' } } + } + } +} + +const enrichedSql = ` + WITH x AS ( + ${indexesSql} + ) + SELECT + x.* + FROM x +` diff --git a/src/lib/PostgresMetaMaterializedViews.ts b/src/lib/PostgresMetaMaterializedViews.ts new file mode 100644 index 00000000..7f1efac5 --- /dev/null +++ b/src/lib/PostgresMetaMaterializedViews.ts @@ -0,0 +1,116 @@ +import { literal } from 'pg-format' +import { coalesceRowsToArray, filterByList } from './helpers.js' +import { columnsSql, materializedViewsSql } from './sql/index.js' +import { PostgresMetaResult, PostgresMaterializedView } from './types.js' + +export default class PostgresMetaMaterializedViews { + query: (sql: string) => Promise> + + constructor(query: (sql: string) => Promise>) { + this.query = query + } + + async list(options: { + includedSchemas?: string[] + excludedSchemas?: string[] + limit?: number + offset?: number + includeColumns: true + }): Promise> + async list(options?: { + includedSchemas?: string[] + excludedSchemas?: string[] + limit?: number + offset?: number + includeColumns?: boolean + }): Promise> + async list({ + includedSchemas, + excludedSchemas, + limit, + offset, + includeColumns = false, + }: { + includedSchemas?: string[] + excludedSchemas?: string[] + limit?: number + offset?: number + includeColumns?: boolean + } = {}): Promise> { + let sql = generateEnrichedMaterializedViewsSql({ includeColumns }) + const filter = filterByList(includedSchemas, excludedSchemas, undefined) + if (filter) { + sql += ` where schema ${filter}` + } + if (limit) { + sql += ` limit ${limit}` + } + if (offset) { + sql += ` offset ${offset}` + } + return await this.query(sql) + } + + async retrieve({ id }: { id: number }): Promise> + async retrieve({ + name, + schema, + }: { + name: string + schema: string + }): Promise> + async retrieve({ + id, + name, + schema = 'public', + }: { + id?: number + name?: string + schema?: string + }): Promise> { + if (id) { + const sql = `${generateEnrichedMaterializedViewsSql({ + includeColumns: true, + })} where materialized_views.id = ${literal(id)};` + const { data, error } = await this.query(sql) + if (error) { + return { data, error } + } else if (data.length === 0) { + return { data: null, error: { message: `Cannot find a materialized view with ID ${id}` } } + } else { + return { data: data[0], error } + } + } else if (name) { + const sql = `${generateEnrichedMaterializedViewsSql({ + includeColumns: true, + })} where materialized_views.name = ${literal( + name + )} and materialized_views.schema = ${literal(schema)};` + const { data, error } = await this.query(sql) + if (error) { + return { data, error } + } else if (data.length === 0) { + return { + data: null, + error: { message: `Cannot find a materialized view named ${name} in schema ${schema}` }, + } + } else { + return { data: data[0], error } + } + } else { + return { data: null, error: { message: 'Invalid parameters on materialized view retrieve' } } + } + } +} + +const generateEnrichedMaterializedViewsSql = ({ includeColumns }: { includeColumns: boolean }) => ` +with materialized_views as (${materializedViewsSql}) + ${includeColumns ? `, columns as (${columnsSql})` : ''} +select + * + ${ + includeColumns + ? `, ${coalesceRowsToArray('columns', 'columns.table_id = materialized_views.id')}` + : '' + } +from materialized_views` diff --git a/src/lib/PostgresMetaPolicies.ts b/src/lib/PostgresMetaPolicies.ts index 93fb2225..fa476c12 100644 --- a/src/lib/PostgresMetaPolicies.ts +++ b/src/lib/PostgresMetaPolicies.ts @@ -1,7 +1,8 @@ import { ident, literal } from 'pg-format' -import { DEFAULT_SYSTEM_SCHEMAS } from './constants' -import { policiesSql } from './sql' -import { PostgresMetaResult, PostgresPolicy } from './types' +import { DEFAULT_SYSTEM_SCHEMAS } from './constants.js' +import { filterByList } from './helpers.js' +import { policiesSql } from './sql/index.js' +import { PostgresMetaResult, PostgresPolicy } from './types.js' export default class PostgresMetaPolicies { query: (sql: string) => Promise> @@ -12,16 +13,25 @@ export default class PostgresMetaPolicies { async list({ includeSystemSchemas = false, + includedSchemas, + excludedSchemas, limit, offset, }: { includeSystemSchemas?: boolean + includedSchemas?: string[] + excludedSchemas?: string[] limit?: number offset?: number } = {}): Promise> { let sql = policiesSql - if (!includeSystemSchemas) { - sql = `${sql} WHERE NOT (n.nspname IN (${DEFAULT_SYSTEM_SCHEMAS.map(literal).join(',')}))` + const filter = filterByList( + includedSchemas, + excludedSchemas, + !includeSystemSchemas ? DEFAULT_SYSTEM_SCHEMAS : undefined + ) + if (filter) { + sql += ` WHERE n.nspname ${filter}` } if (limit) { sql = `${sql} LIMIT ${limit}` @@ -91,7 +101,7 @@ export default class PostgresMetaPolicies { check, action = 'PERMISSIVE', command = 'ALL', - roles = ['PUBLIC'], + roles = ['public'], }: { name: string table: string @@ -108,7 +118,7 @@ export default class PostgresMetaPolicies { CREATE POLICY ${ident(name)} ON ${ident(schema)}.${ident(table)} AS ${action} FOR ${command} - TO ${roles.join(',')} + TO ${roles.map(ident).join(',')} ${definitionClause} ${checkClause};` const { error } = await this.query(sql) if (error) { @@ -140,7 +150,7 @@ CREATE POLICY ${ident(name)} ON ${ident(schema)}.${ident(table)} const nameSql = name === undefined ? '' : `${alter} RENAME TO ${ident(name)};` const definitionSql = definition === undefined ? '' : `${alter} USING (${definition});` const checkSql = check === undefined ? '' : `${alter} WITH CHECK (${check});` - const rolesSql = roles === undefined ? '' : `${alter} TO (${roles.join(',')});` + const rolesSql = roles === undefined ? '' : `${alter} TO ${roles.map(ident).join(',')};` // nameSql must be last const sql = `BEGIN; ${definitionSql} ${checkSql} ${rolesSql} ${nameSql} COMMIT;` diff --git a/src/lib/PostgresMetaPublications.ts b/src/lib/PostgresMetaPublications.ts index ec5104e1..63c1bafe 100644 --- a/src/lib/PostgresMetaPublications.ts +++ b/src/lib/PostgresMetaPublications.ts @@ -1,6 +1,6 @@ import { ident, literal } from 'pg-format' -import { publicationsSql } from './sql' -import { PostgresMetaResult, PostgresPublication, PostgresTable } from './types' +import { publicationsSql } from './sql/index.js' +import { PostgresMetaResult, PostgresPublication, PostgresTable } from './types.js' export default class PostgresMetaPublications { query: (sql: string) => Promise> @@ -66,17 +66,17 @@ export default class PostgresMetaPublications { publish_update = false, publish_delete = false, publish_truncate = false, - tables, + tables = null, }: { name: string publish_insert?: boolean publish_update?: boolean publish_delete?: boolean publish_truncate?: boolean - tables?: string[] + tables?: string[] | null }): Promise> { let tableClause: string - if (tables === undefined) { + if (tables === undefined || tables === null) { tableClause = 'FOR ALL TABLES' } else if (tables.length === 0) { tableClause = '' @@ -127,87 +127,109 @@ CREATE PUBLICATION ${ident(name)} ${tableClause} publish_update?: boolean publish_delete?: boolean publish_truncate?: boolean - tables?: string[] + tables?: string[] | null } ): Promise> { - const { data: old, error } = await this.retrieve({ id }) + const sql = ` +do $$ +declare + id oid := ${literal(id)}; + old record; + new_name text := ${name === undefined ? null : literal(name)}; + new_owner text := ${owner === undefined ? null : literal(owner)}; + new_publish_insert bool := ${publish_insert ?? null}; + new_publish_update bool := ${publish_update ?? null}; + new_publish_delete bool := ${publish_delete ?? null}; + new_publish_truncate bool := ${publish_truncate ?? null}; + new_tables text := ${ + tables === undefined + ? null + : literal( + tables === null + ? 'all tables' + : tables + .map((t) => { + if (!t.includes('.')) { + return ident(t) + } + + const [schema, ...rest] = t.split('.') + const table = rest.join('.') + return `${ident(schema)}.${ident(table)}` + }) + .join(',') + ) + }; +begin + select * into old from pg_publication where oid = id; + if old is null then + raise exception 'Cannot find publication with id %', id; + end if; + + if new_tables is null then + null; + elsif new_tables = 'all tables' then + if old.puballtables then + null; + else + -- Need to recreate because going from list of tables <-> all tables with alter is not possible. + execute(format('drop publication %1$I; create publication %1$I for all tables;', old.pubname)); + end if; + else + if old.puballtables then + -- Need to recreate because going from list of tables <-> all tables with alter is not possible. + execute(format('drop publication %1$I; create publication %1$I;', old.pubname)); + elsif exists(select from pg_publication_rel where prpubid = id) then + execute( + format( + 'alter publication %I drop table %s', + old.pubname, + (select string_agg(prrelid::regclass::text, ', ') from pg_publication_rel where prpubid = id) + ) + ); + end if; + + -- At this point the publication must have no tables. + + if new_tables != '' then + execute(format('alter publication %I add table %s', old.pubname, new_tables)); + end if; + end if; + + execute( + format( + 'alter publication %I set (publish = %L);', + old.pubname, + concat_ws( + ', ', + case when coalesce(new_publish_insert, old.pubinsert) then 'insert' end, + case when coalesce(new_publish_update, old.pubupdate) then 'update' end, + case when coalesce(new_publish_delete, old.pubdelete) then 'delete' end, + case when coalesce(new_publish_truncate, old.pubtruncate) then 'truncate' end + ) + ) + ); + + execute(format('alter publication %I owner to %I;', old.pubname, coalesce(new_owner, old.pubowner::regrole::name))); + + -- Using the same name in the rename clause gives an error, so only do it if the new name is different. + if new_name is not null and new_name != old.pubname then + execute(format('alter publication %I rename to %I;', old.pubname, coalesce(new_name, old.pubname))); + end if; + + -- We need to retrieve the publication later, so we need a way to uniquely identify which publication this is. + -- We can't rely on id because it gets changed if it got recreated. + -- We use a temp table to store the unique name - DO blocks can't return a value. + create temp table pg_meta_publication_tmp (name) on commit drop as values (coalesce(new_name, old.pubname)); +end $$; + +with publications as (${publicationsSql}) select * from publications where name = (select name from pg_meta_publication_tmp); +` + const { data, error } = await this.query(sql) if (error) { return { data: null, error } } - - // Need to work around the limitations of the SQL. Can't add/drop tables from - // a publication with FOR ALL TABLES. Can't use the SET TABLE clause without - // at least one table. - // - // new tables - // - // | undefined | string[] | - // ---------|-----------|-----------------| - // null | '' | 400 Bad Request | - // old tables ---------|-----------|-----------------| - // object[] | '' | See below | - // - // new tables - // - // | [] | [...] | - // ---------|-----------|-----------------| - // [] | '' | SET TABLE | - // old tables ---------|-----------|-----------------| - // [...] | DROP all | SET TABLE | - // - let tableSql: string - if (tables === undefined) { - tableSql = '' - } else if (old!.tables === null) { - throw new Error('Tables cannot be added to or dropped from FOR ALL TABLES publications') - } else if (tables.length > 0) { - tableSql = `ALTER PUBLICATION ${ident(old!.name)} SET TABLE ${tables - .map((t) => { - if (!t.includes('.')) { - return ident(t) - } - - const [schema, ...rest] = t.split('.') - const table = rest.join('.') - return `${ident(schema)}.${ident(table)}` - }) - .join(',')};` - } else if (old!.tables.length === 0) { - tableSql = '' - } else { - tableSql = `ALTER PUBLICATION ${ident(old!.name)} DROP TABLE ${old!.tables - .map( - (table: { schema: string; name: string }) => `${ident(table.schema)}.${ident(table.name)}` - ) - .join(',')};` - } - - let publishOps = [] - if (publish_insert ?? old!.publish_insert) publishOps.push('insert') - if (publish_update ?? old!.publish_update) publishOps.push('update') - if (publish_delete ?? old!.publish_delete) publishOps.push('delete') - if (publish_truncate ?? old!.publish_truncate) publishOps.push('truncate') - const publishSql = `ALTER PUBLICATION ${ident(old!.name)} SET (publish = '${publishOps.join( - ',' - )}');` - - const ownerSql = - owner === undefined ? '' : `ALTER PUBLICATION ${ident(old!.name)} OWNER TO ${ident(owner)};` - - const nameSql = - name === undefined || name === old!.name - ? '' - : `ALTER PUBLICATION ${ident(old!.name)} RENAME TO ${ident(name)};` - - // nameSql must be last - const sql = `BEGIN; ${tableSql} ${publishSql} ${ownerSql} ${nameSql} COMMIT;` - { - const { error } = await this.query(sql) - if (error) { - return { data: null, error } - } - } - return await this.retrieve({ id }) + return { data: data[0], error } } async remove(id: number): Promise> { diff --git a/src/lib/PostgresMetaRelationships.ts b/src/lib/PostgresMetaRelationships.ts new file mode 100644 index 00000000..059762c3 --- /dev/null +++ b/src/lib/PostgresMetaRelationships.ts @@ -0,0 +1,154 @@ +import { literal } from 'pg-format' +import { DEFAULT_SYSTEM_SCHEMAS } from './constants.js' +import { tableRelationshipsSql, viewsKeyDependenciesSql } from './sql/index.js' +import { PostgresMetaResult, PostgresRelationship } from './types.js' + +/* + * Only used for generating types at the moment. Will need some cleanups before + * using it for other things, e.g. /relationships endpoint. + */ +export default class PostgresMetaRelationships { + query: (sql: string) => Promise> + + constructor(query: (sql: string) => Promise>) { + this.query = query + } + + async list(): Promise> { + let allTableM2oAndO2oRelationships: PostgresRelationship[] + { + let sql = tableRelationshipsSql + const { data, error } = (await this.query(sql)) as PostgresMetaResult + if (error) { + return { data: null, error } + } + allTableM2oAndO2oRelationships = data + } + + /* + * Adapted from: + * https://github.com/PostgREST/postgrest/blob/f9f0f79fa914ac00c11fbf7f4c558e14821e67e2/src/PostgREST/SchemaCache.hs#L392 + */ + let allViewM2oAndO2oRelationships: PostgresRelationship[] + { + type ColDep = { + table_column: string + view_columns: string[] + } + type KeyDep = { + table_schema: string + table_name: string + view_schema: string + view_name: string + constraint_name: string + constraint_type: 'f' | 'f_ref' | 'p' | 'p_ref' + column_dependencies: ColDep[] + } + + const { data: viewsKeyDependencies, error } = (await this.query( + allViewsKeyDependenciesSql + )) as PostgresMetaResult + if (error) { + return { data: null, error } + } + + const viewRelationships = allTableM2oAndO2oRelationships.flatMap((r) => { + const expandKeyDepCols = ( + colDeps: ColDep[] + ): { tableColumns: string[]; viewColumns: string[] }[] => { + const tableColumns = colDeps.map(({ table_column }) => table_column) + // https://gist.github.com/ssippe/1f92625532eef28be6974f898efb23ef?permalink_comment_id=3474581#gistcomment-3474581 + const cartesianProduct = (allEntries: T[][]): T[][] => { + return allEntries.reduce( + (results, entries) => + results + .map((result) => entries.map((entry) => [...result, entry])) + .reduce((subResults, result) => [...subResults, ...result], []), + [[]] + ) + } + const viewColumnsPermutations = cartesianProduct(colDeps.map((cd) => cd.view_columns)) + return viewColumnsPermutations.map((viewColumns) => ({ tableColumns, viewColumns })) + } + + const viewToTableKeyDeps = viewsKeyDependencies.filter( + (vkd) => + vkd.table_schema === r.schema && + vkd.table_name === r.relation && + vkd.constraint_name === r.foreign_key_name && + vkd.constraint_type === 'f' + ) + const tableToViewKeyDeps = viewsKeyDependencies.filter( + (vkd) => + vkd.table_schema === r.referenced_schema && + vkd.table_name === r.referenced_relation && + vkd.constraint_name === r.foreign_key_name && + vkd.constraint_type === 'f_ref' + ) + + const viewToTableRelationships = viewToTableKeyDeps.flatMap((vtkd) => + expandKeyDepCols(vtkd.column_dependencies).map(({ viewColumns }) => ({ + foreign_key_name: r.foreign_key_name, + schema: vtkd.view_schema, + relation: vtkd.view_name, + columns: viewColumns, + is_one_to_one: r.is_one_to_one, + referenced_schema: r.referenced_schema, + referenced_relation: r.referenced_relation, + referenced_columns: r.referenced_columns, + })) + ) + + const tableToViewRelationships = tableToViewKeyDeps.flatMap((tvkd) => + expandKeyDepCols(tvkd.column_dependencies).map(({ viewColumns }) => ({ + foreign_key_name: r.foreign_key_name, + schema: r.schema, + relation: r.relation, + columns: r.columns, + is_one_to_one: r.is_one_to_one, + referenced_schema: tvkd.view_schema, + referenced_relation: tvkd.view_name, + referenced_columns: viewColumns, + })) + ) + + const viewToViewRelationships = viewToTableKeyDeps.flatMap((vtkd) => + expandKeyDepCols(vtkd.column_dependencies).flatMap(({ viewColumns }) => + tableToViewKeyDeps.flatMap((tvkd) => + expandKeyDepCols(tvkd.column_dependencies).map( + ({ viewColumns: referencedViewColumns }) => ({ + foreign_key_name: r.foreign_key_name, + schema: vtkd.view_schema, + relation: vtkd.view_name, + columns: viewColumns, + is_one_to_one: r.is_one_to_one, + referenced_schema: tvkd.view_schema, + referenced_relation: tvkd.view_name, + referenced_columns: referencedViewColumns, + }) + ) + ) + ) + ) + + return [ + ...viewToTableRelationships, + ...tableToViewRelationships, + ...viewToViewRelationships, + ] + }) + + allViewM2oAndO2oRelationships = viewRelationships + } + + return { + data: allTableM2oAndO2oRelationships.concat(allViewM2oAndO2oRelationships), + error: null, + } + } +} + +const allViewsKeyDependenciesSql = viewsKeyDependenciesSql.replaceAll( + '__EXCLUDED_SCHEMAS', + literal(DEFAULT_SYSTEM_SCHEMAS) +) diff --git a/src/lib/PostgresMetaRoles.ts b/src/lib/PostgresMetaRoles.ts index e631e84e..f55fb4a9 100644 --- a/src/lib/PostgresMetaRoles.ts +++ b/src/lib/PostgresMetaRoles.ts @@ -1,9 +1,21 @@ import { ident, literal } from 'pg-format' -import { DEFAULT_ROLES, DEFAULT_SYSTEM_SCHEMAS } from './constants' -import { coalesceRowsToArray } from './helpers' -import { grantsSql, rolesSql } from './sql' -import { PostgresMetaResult, PostgresRole } from './types' - +import { rolesSql } from './sql/index.js' +import { + PostgresMetaResult, + PostgresRole, + PostgresRoleCreate, + PostgresRoleUpdate, +} from './types.js' +export function changeRoleConfig2Object(config: string[]) { + if (!config) { + return null + } + return config.reduce((acc: any, cur) => { + const [key, value] = cur.split('=') + acc[key] = value + return acc + }, {}) +} export default class PostgresMetaRoles { query: (sql: string) => Promise> @@ -13,38 +25,47 @@ export default class PostgresMetaRoles { async list({ includeDefaultRoles = false, - includeSystemSchemas = false, limit, offset, }: { includeDefaultRoles?: boolean - includeSystemSchemas?: boolean limit?: number offset?: number } = {}): Promise> { let sql = ` -WITH roles AS (${ - includeDefaultRoles - ? rolesSql - : `${rolesSql} WHERE NOT (rolname IN (${DEFAULT_ROLES.map(literal).join(',')}))` - }), - grants AS (${ - includeSystemSchemas - ? grantsSql - : `${grantsSql} AND NOT (nc.nspname IN (${DEFAULT_SYSTEM_SCHEMAS.map(literal).join(',')}))` - }) +WITH + roles AS (${rolesSql}) SELECT - *, - ${coalesceRowsToArray('grants', 'grants.grantee = roles.name')} + * FROM - roles` + roles +WHERE + true` + if (!includeDefaultRoles) { + // All default/predefined roles start with pg_: https://www.postgresql.org/docs/15/predefined-roles.html + // The pg_ prefix is also reserved: + // + // ``` + // postgres=# create role pg_mytmp; + // ERROR: role name "pg_mytmp" is reserved + // DETAIL: Role names starting with "pg_" are reserved. + // ``` + sql += ` AND NOT pg_catalog.starts_with(name, 'pg_')` + } if (limit) { - sql = `${sql} LIMIT ${limit}` + sql += ` LIMIT ${limit}` } if (offset) { - sql = `${sql} OFFSET ${offset}` + sql += ` OFFSET ${offset}` + } + const result = await this.query(sql) + if (result.data) { + result.data = result.data.map((role: any) => { + role.config = changeRoleConfig2Object(role.config) + return role + }) } - return await this.query(sql) + return result } async retrieve({ id }: { id: number }): Promise> @@ -59,11 +80,13 @@ FROM if (id) { const sql = `${rolesSql} WHERE oid = ${literal(id)};` const { data, error } = await this.query(sql) + if (error) { return { data, error } } else if (data.length === 0) { return { data: null, error: { message: `Cannot find a role with ID ${id}` } } } else { + data[0].config = changeRoleConfig2Object(data[0].config) return { data: data[0], error } } } else if (name) { @@ -74,6 +97,7 @@ FROM } else if (data.length === 0) { return { data: null, error: { message: `Cannot find a role named ${name}` } } } else { + data[0].config = changeRoleConfig2Object(data[0].config) return { data: data[0], error } } } else { @@ -96,22 +120,8 @@ FROM member_of, members, admins, - }: { - name: string - is_superuser?: boolean - can_create_db?: boolean - can_create_role?: boolean - inherit_role?: boolean - can_login?: boolean - is_replication_role?: boolean - can_bypass_rls?: boolean - connection_limit?: number - password?: string - valid_until?: string - member_of?: string[] - members?: string[] - admins?: string[] - }): Promise> { + config, + }: PostgresRoleCreate): Promise> { const isSuperuserClause = is_superuser ? 'SUPERUSER' : 'NOSUPERUSER' const canCreateDbClause = can_create_db ? 'CREATEDB' : 'NOCREATEDB' const canCreateRoleClause = can_create_role ? 'CREATEROLE' : 'NOCREATEROLE' @@ -125,8 +135,20 @@ FROM const memberOfClause = member_of === undefined ? '' : `IN ROLE ${member_of.join(',')}` const membersClause = members === undefined ? '' : `ROLE ${members.join(',')}` const adminsClause = admins === undefined ? '' : `ADMIN ${admins.join(',')}` - + let configClause = '' + if (config !== undefined) { + configClause = Object.keys(config) + .map((k) => { + const v = config[k] + if (!k || !v) { + return '' + } + return `ALTER ROLE ${name} SET ${k} = ${v};` + }) + .join('\n') + } const sql = ` +BEGIN; CREATE ROLE ${ident(name)} WITH ${isSuperuserClause} @@ -141,7 +163,9 @@ WITH ${validUntilClause} ${memberOfClause} ${membersClause} - ${adminsClause};` + ${adminsClause}; +${configClause ? configClause : ''} +COMMIT;` const { error } = await this.query(sql) if (error) { return { data: null, error } @@ -163,19 +187,8 @@ WITH connection_limit, password, valid_until, - }: { - name?: string - is_superuser?: boolean - can_create_db?: boolean - can_create_role?: boolean - inherit_role?: boolean - can_login?: boolean - is_replication_role?: boolean - can_bypass_rls?: boolean - connection_limit?: number - password?: string - valid_until?: string - } + config, + }: PostgresRoleUpdate ): Promise> { const { data: old, error } = await this.retrieve({ id }) if (error) { @@ -216,7 +229,27 @@ WITH connection_limit === undefined ? '' : `CONNECTION LIMIT ${connection_limit}` const passwordClause = password === undefined ? '' : `PASSWORD ${literal(password)}` const validUntilClause = valid_until === undefined ? '' : `VALID UNTIL ${literal(valid_until)}` - + let configClause = '' + if (config !== undefined) { + const configSql = config.map((c) => { + const { op, path, value } = c + const k = path + const v = value || null + if (!k) { + throw new Error(`Invalid config value ${value}`) + } + switch (op) { + case 'add': + case 'replace': + return `ALTER ROLE ${ident(old!.name)} SET ${ident(k)} = ${literal(v)};` + case 'remove': + return `ALTER ROLE ${ident(old!.name)} RESET ${ident(k)};` + default: + throw new Error(`Invalid config op ${op}`) + } + }) + configClause = configSql.filter(Boolean).join('') + } // nameSql must be last const sql = ` BEGIN; @@ -231,6 +264,7 @@ BEGIN; ${connectionLimitClause} ${passwordClause} ${validUntilClause}; + ${configClause ? configClause : ''} ${nameSql} COMMIT;` { diff --git a/src/lib/PostgresMetaSchemas.ts b/src/lib/PostgresMetaSchemas.ts index 2b8e1f6b..b84a64cc 100644 --- a/src/lib/PostgresMetaSchemas.ts +++ b/src/lib/PostgresMetaSchemas.ts @@ -1,12 +1,12 @@ import { ident, literal } from 'pg-format' -import { DEFAULT_SYSTEM_SCHEMAS } from './constants' -import { schemasSql } from './sql' +import { DEFAULT_SYSTEM_SCHEMAS } from './constants.js' +import { schemasSql } from './sql/index.js' import { PostgresMetaResult, PostgresSchema, PostgresSchemaCreate, PostgresSchemaUpdate, -} from './types' +} from './types.js' export default class PostgresMetaSchemas { query: (sql: string) => Promise> diff --git a/src/lib/PostgresMetaTablePrivileges.ts b/src/lib/PostgresMetaTablePrivileges.ts new file mode 100644 index 00000000..9edb32e9 --- /dev/null +++ b/src/lib/PostgresMetaTablePrivileges.ts @@ -0,0 +1,170 @@ +import { ident, literal } from 'pg-format' +import { DEFAULT_SYSTEM_SCHEMAS } from './constants.js' +import { filterByList } from './helpers.js' +import { tablePrivilegesSql } from './sql/index.js' +import { + PostgresMetaResult, + PostgresTablePrivileges, + PostgresTablePrivilegesGrant, + PostgresTablePrivilegesRevoke, +} from './types.js' + +export default class PostgresMetaTablePrivileges { + query: (sql: string) => Promise> + + constructor(query: (sql: string) => Promise>) { + this.query = query + } + + async list({ + includeSystemSchemas = false, + includedSchemas, + excludedSchemas, + limit, + offset, + }: { + includeSystemSchemas?: boolean + includedSchemas?: string[] + excludedSchemas?: string[] + limit?: number + offset?: number + } = {}): Promise> { + let sql = ` +with table_privileges as (${tablePrivilegesSql}) +select * +from table_privileges +` + const filter = filterByList( + includedSchemas, + excludedSchemas, + !includeSystemSchemas ? DEFAULT_SYSTEM_SCHEMAS : undefined + ) + if (filter) { + sql += ` where schema ${filter}` + } + if (limit) { + sql += ` limit ${limit}` + } + if (offset) { + sql += ` offset ${offset}` + } + return await this.query(sql) + } + + async retrieve({ id }: { id: number }): Promise> + async retrieve({ + name, + schema, + }: { + name: string + schema: string + }): Promise> + async retrieve({ + id, + name, + schema = 'public', + }: { + id?: number + name?: string + schema?: string + }): Promise> { + if (id) { + const sql = ` +with table_privileges as (${tablePrivilegesSql}) +select * +from table_privileges +where table_privileges.relation_id = ${literal(id)};` + const { data, error } = await this.query(sql) + if (error) { + return { data, error } + } else if (data.length === 0) { + return { data: null, error: { message: `Cannot find a relation with ID ${id}` } } + } else { + return { data: data[0], error } + } + } else if (name) { + const sql = ` +with table_privileges as (${tablePrivilegesSql}) +select * +from table_privileges +where table_privileges.schema = ${literal(schema)} + and table_privileges.name = ${literal(name)} +` + const { data, error } = await this.query(sql) + if (error) { + return { data, error } + } else if (data.length === 0) { + return { + data: null, + error: { message: `Cannot find a relation named ${name} in schema ${schema}` }, + } + } else { + return { data: data[0], error } + } + } else { + return { data: null, error: { message: 'Invalid parameters on retrieving table privileges' } } + } + } + + async grant( + grants: PostgresTablePrivilegesGrant[] + ): Promise> { + let sql = ` +do $$ +begin +${grants + .map( + ({ privilege_type, relation_id, grantee, is_grantable }) => + `execute format('grant ${privilege_type} on table %s to ${ + grantee.toLowerCase() === 'public' ? 'public' : ident(grantee) + } ${is_grantable ? 'with grant option' : ''}', ${relation_id}::regclass);` + ) + .join('\n')} +end $$; +` + const { data, error } = await this.query(sql) + if (error) { + return { data, error } + } + + // Return the updated table privileges for modified relations. + const relationIds = [...new Set(grants.map(({ relation_id }) => relation_id))] + sql = ` +with table_privileges as (${tablePrivilegesSql}) +select * +from table_privileges +where relation_id in (${relationIds.map(literal).join(',')}) +` + return await this.query(sql) + } + + async revoke( + revokes: PostgresTablePrivilegesRevoke[] + ): Promise> { + let sql = ` +do $$ +begin +${revokes + .map( + (revoke) => + `execute format('revoke ${revoke.privilege_type} on table %s from ${revoke.grantee}', ${revoke.relation_id}::regclass);` + ) + .join('\n')} +end $$; +` + const { data, error } = await this.query(sql) + if (error) { + return { data, error } + } + + // Return the updated table privileges for modified relations. + const relationIds = [...new Set(revokes.map(({ relation_id }) => relation_id))] + sql = ` +with table_privileges as (${tablePrivilegesSql}) +select * +from table_privileges +where relation_id in (${relationIds.map(literal).join(',')}) +` + return await this.query(sql) + } +} diff --git a/src/lib/PostgresMetaTables.ts b/src/lib/PostgresMetaTables.ts index 2b7311f7..5b97c253 100644 --- a/src/lib/PostgresMetaTables.ts +++ b/src/lib/PostgresMetaTables.ts @@ -1,15 +1,13 @@ import { ident, literal } from 'pg-format' -import { DEFAULT_SYSTEM_SCHEMAS } from './constants' -import { coalesceRowsToArray } from './helpers' +import { DEFAULT_SYSTEM_SCHEMAS } from './constants.js' +import { coalesceRowsToArray, filterByList } from './helpers.js' +import { columnsSql, tablesSql } from './sql/index.js' import { - columnsSql, - grantsSql, - policiesSql, - primaryKeysSql, - relationshipsSql, - tablesSql, -} from './sql' -import { PostgresMetaResult, PostgresTable } from './types' + PostgresMetaResult, + PostgresTable, + PostgresTableCreate, + PostgresTableUpdate, +} from './types.js' export default class PostgresMetaTables { query: (sql: string) => Promise> @@ -18,24 +16,51 @@ export default class PostgresMetaTables { this.query = query } + async list(options: { + includeSystemSchemas?: boolean + includedSchemas?: string[] + excludedSchemas?: string[] + limit?: number + offset?: number + includeColumns: false + }): Promise> + async list(options?: { + includeSystemSchemas?: boolean + includedSchemas?: string[] + excludedSchemas?: string[] + limit?: number + offset?: number + includeColumns?: boolean + }): Promise> async list({ includeSystemSchemas = false, + includedSchemas, + excludedSchemas, limit, offset, + includeColumns = true, }: { includeSystemSchemas?: boolean + includedSchemas?: string[] + excludedSchemas?: string[] limit?: number offset?: number + includeColumns?: boolean } = {}): Promise> { - let sql = enrichedTablesSql - if (!includeSystemSchemas) { - sql = `${sql} WHERE NOT (schema IN (${DEFAULT_SYSTEM_SCHEMAS.map(literal).join(',')}))` + let sql = generateEnrichedTablesSql({ includeColumns }) + const filter = filterByList( + includedSchemas, + excludedSchemas, + !includeSystemSchemas ? DEFAULT_SYSTEM_SCHEMAS : undefined + ) + if (filter) { + sql += ` where schema ${filter}` } if (limit) { - sql = `${sql} LIMIT ${limit}` + sql += ` limit ${limit}` } if (offset) { - sql = `${sql} OFFSET ${offset}` + sql += ` offset ${offset}` } return await this.query(sql) } @@ -58,7 +83,9 @@ export default class PostgresMetaTables { schema?: string }): Promise> { if (id) { - const sql = `${enrichedTablesSql} WHERE tables.id = ${literal(id)};` + const sql = `${generateEnrichedTablesSql({ + includeColumns: true, + })} where tables.id = ${literal(id)};` const { data, error } = await this.query(sql) if (error) { return { data, error } @@ -68,9 +95,9 @@ export default class PostgresMetaTables { return { data: data[0], error } } } else if (name) { - const sql = `${enrichedTablesSql} WHERE tables.name = ${literal( - name - )} AND tables.schema = ${literal(schema)};` + const sql = `${generateEnrichedTablesSql({ + includeColumns: true, + })} where tables.name = ${literal(name)} and tables.schema = ${literal(schema)};` const { data, error } = await this.query(sql) if (error) { return { data, error } @@ -91,11 +118,7 @@ export default class PostgresMetaTables { name, schema = 'public', comment, - }: { - name: string - schema?: string - comment?: string - }): Promise> { + }: PostgresTableCreate): Promise> { const tableSql = `CREATE TABLE ${ident(schema)}.${ident(name)} ();` const commentSql = comment === undefined @@ -120,16 +143,7 @@ export default class PostgresMetaTables { replica_identity_index, primary_keys, comment, - }: { - name?: string - schema?: string - rls_enabled?: boolean - rls_forced?: boolean - replica_identity?: 'DEFAULT' | 'INDEX' | 'FULL' | 'NOTHING' - replica_identity_index?: string - primary_keys?: { name: string }[] - comment?: string - } + }: PostgresTableUpdate ): Promise> { const { data: old, error } = await this.retrieve({ id }) if (error) { @@ -233,22 +247,10 @@ COMMIT;` } } -const enrichedTablesSql = ` -WITH tables AS (${tablesSql}), - columns AS (${columnsSql}), - grants AS (${grantsSql}), - policies AS (${policiesSql}), - primary_keys AS (${primaryKeysSql}), - relationships AS (${relationshipsSql}) -SELECT - *, - ${coalesceRowsToArray('columns', 'columns.table_id = tables.id')}, - ${coalesceRowsToArray('grants', 'grants.table_id = tables.id')}, - ${coalesceRowsToArray('policies', 'policies.table_id = tables.id')}, - ${coalesceRowsToArray('primary_keys', 'primary_keys.table_id = tables.id')}, - ${coalesceRowsToArray( - 'relationships', - `(relationships.source_schema = tables.schema AND relationships.source_table_name = tables.name) - OR (relationships.target_table_schema = tables.schema AND relationships.target_table_name = tables.name)` - )} -FROM tables` +const generateEnrichedTablesSql = ({ includeColumns }: { includeColumns: boolean }) => ` +with tables as (${tablesSql}) + ${includeColumns ? `, columns as (${columnsSql})` : ''} +select + * + ${includeColumns ? `, ${coalesceRowsToArray('columns', 'columns.table_id = tables.id')}` : ''} +from tables` diff --git a/src/lib/PostgresMetaTriggers.ts b/src/lib/PostgresMetaTriggers.ts index e3cc9655..5ce05f76 100644 --- a/src/lib/PostgresMetaTriggers.ts +++ b/src/lib/PostgresMetaTriggers.ts @@ -1,6 +1,8 @@ import { ident, literal } from 'pg-format' -import { triggersSql } from './sql' -import { PostgresMetaResult, PostgresTrigger } from './types' +import { DEFAULT_SYSTEM_SCHEMAS } from './constants.js' +import { filterByList } from './helpers.js' +import { triggersSql } from './sql/index.js' +import { PostgresMetaResult, PostgresTrigger } from './types.js' export default class PostgresMetaTriggers { query: (sql: string) => Promise> @@ -10,13 +12,27 @@ export default class PostgresMetaTriggers { } async list({ + includeSystemSchemas = false, + includedSchemas, + excludedSchemas, limit, offset, }: { + includeSystemSchemas?: boolean + includedSchemas?: string[] + excludedSchemas?: string[] limit?: number offset?: number } = {}): Promise> { let sql = enrichedTriggersSql + const filter = filterByList( + includedSchemas, + excludedSchemas, + !includeSystemSchemas ? DEFAULT_SYSTEM_SCHEMAS : undefined + ) + if (filter) { + sql += ` WHERE schema ${filter}` + } if (limit) { sql = `${sql} LIMIT ${limit}` } diff --git a/src/lib/PostgresMetaTypes.ts b/src/lib/PostgresMetaTypes.ts index 33f57b1a..35371d55 100644 --- a/src/lib/PostgresMetaTypes.ts +++ b/src/lib/PostgresMetaTypes.ts @@ -1,7 +1,7 @@ -import { literal } from 'pg-format' -import { DEFAULT_SYSTEM_SCHEMAS } from './constants' -import { typesSql } from './sql' -import { PostgresMetaResult, PostgresType } from './types' +import { DEFAULT_SYSTEM_SCHEMAS } from './constants.js' +import { filterByList } from './helpers.js' +import { typesSql } from './sql/index.js' +import { PostgresMetaResult, PostgresType } from './types.js' export default class PostgresMetaTypes { query: (sql: string) => Promise> @@ -11,23 +11,59 @@ export default class PostgresMetaTypes { } async list({ + includeTableTypes = false, + includeArrayTypes = false, includeSystemSchemas = false, + includedSchemas, + excludedSchemas, limit, offset, }: { + includeTableTypes?: boolean + includeArrayTypes?: boolean includeSystemSchemas?: boolean + includedSchemas?: string[] + excludedSchemas?: string[] limit?: number offset?: number } = {}): Promise> { - let sql = typesSql - if (!includeSystemSchemas) { - sql = `${sql} AND NOT (n.nspname IN (${DEFAULT_SYSTEM_SCHEMAS.map(literal).join(',')}))` + let sql = `${typesSql} + where + ( + t.typrelid = 0 + or ( + select + c.relkind ${includeTableTypes ? `in ('c', 'r')` : `= 'c'`} + from + pg_class c + where + c.oid = t.typrelid + ) + ) + ` + if (!includeArrayTypes) { + sql += ` and not exists ( + select + from + pg_type el + where + el.oid = t.typelem + and el.typarray = t.oid + )` + } + const filter = filterByList( + includedSchemas, + excludedSchemas, + !includeSystemSchemas ? DEFAULT_SYSTEM_SCHEMAS : undefined + ) + if (filter) { + sql += ` and n.nspname ${filter}` } if (limit) { - sql = `${sql} LIMIT ${limit}` + sql += ` limit ${limit}` } if (offset) { - sql = `${sql} OFFSET ${offset}` + sql += ` offset ${offset}` } return await this.query(sql) } diff --git a/src/lib/PostgresMetaVersion.ts b/src/lib/PostgresMetaVersion.ts index 184991f0..38e0299f 100644 --- a/src/lib/PostgresMetaVersion.ts +++ b/src/lib/PostgresMetaVersion.ts @@ -1,5 +1,5 @@ -import { versionSql } from './sql' -import { PostgresMetaResult, PostgresVersion } from './types' +import { versionSql } from './sql/index.js' +import { PostgresMetaResult, PostgresVersion } from './types.js' export default class PostgresMetaVersion { query: (sql: string) => Promise> diff --git a/src/lib/PostgresMetaViews.ts b/src/lib/PostgresMetaViews.ts index 5ec011e7..0f6ad09c 100644 --- a/src/lib/PostgresMetaViews.ts +++ b/src/lib/PostgresMetaViews.ts @@ -1,7 +1,8 @@ import { literal } from 'pg-format' -import { DEFAULT_SYSTEM_SCHEMAS } from './constants' -import { viewsSql } from './sql' -import { PostgresMetaResult, PostgresView } from './types' +import { DEFAULT_SYSTEM_SCHEMAS } from './constants.js' +import { coalesceRowsToArray, filterByList } from './helpers.js' +import { columnsSql, viewsSql } from './sql/index.js' +import { PostgresMetaResult, PostgresView } from './types.js' export default class PostgresMetaViews { query: (sql: string) => Promise> @@ -10,25 +11,109 @@ export default class PostgresMetaViews { this.query = query } + async list(options: { + includeSystemSchemas?: boolean + includedSchemas?: string[] + excludedSchemas?: string[] + limit?: number + offset?: number + includeColumns: false + }): Promise> + async list(options?: { + includeSystemSchemas?: boolean + includedSchemas?: string[] + excludedSchemas?: string[] + limit?: number + offset?: number + includeColumns?: boolean + }): Promise> async list({ includeSystemSchemas = false, + includedSchemas, + excludedSchemas, limit, offset, + includeColumns = true, }: { includeSystemSchemas?: boolean + includedSchemas?: string[] + excludedSchemas?: string[] limit?: number offset?: number + includeColumns?: boolean } = {}): Promise> { - let sql = viewsSql - if (!includeSystemSchemas) { - sql = `${sql} AND n.nspname NOT IN (${DEFAULT_SYSTEM_SCHEMAS.map(literal).join(',')})` + let sql = generateEnrichedViewsSql({ includeColumns }) + const filter = filterByList( + includedSchemas, + excludedSchemas, + !includeSystemSchemas ? DEFAULT_SYSTEM_SCHEMAS : undefined + ) + if (filter) { + sql += ` where schema ${filter}` } if (limit) { - sql = `${sql} LIMIT ${limit}` + sql += ` limit ${limit}` } if (offset) { - sql = `${sql} OFFSET ${offset}` + sql += ` offset ${offset}` } return await this.query(sql) } + + async retrieve({ id }: { id: number }): Promise> + async retrieve({ + name, + schema, + }: { + name: string + schema: string + }): Promise> + async retrieve({ + id, + name, + schema = 'public', + }: { + id?: number + name?: string + schema?: string + }): Promise> { + if (id) { + const sql = `${generateEnrichedViewsSql({ + includeColumns: true, + })} where views.id = ${literal(id)};` + const { data, error } = await this.query(sql) + if (error) { + return { data, error } + } else if (data.length === 0) { + return { data: null, error: { message: `Cannot find a view with ID ${id}` } } + } else { + return { data: data[0], error } + } + } else if (name) { + const sql = `${generateEnrichedViewsSql({ + includeColumns: true, + })} where views.name = ${literal(name)} and views.schema = ${literal(schema)};` + const { data, error } = await this.query(sql) + if (error) { + return { data, error } + } else if (data.length === 0) { + return { + data: null, + error: { message: `Cannot find a view named ${name} in schema ${schema}` }, + } + } else { + return { data: data[0], error } + } + } else { + return { data: null, error: { message: 'Invalid parameters on view retrieve' } } + } + } } + +const generateEnrichedViewsSql = ({ includeColumns }: { includeColumns: boolean }) => ` +with views as (${viewsSql}) + ${includeColumns ? `, columns as (${columnsSql})` : ''} +select + * + ${includeColumns ? `, ${coalesceRowsToArray('columns', 'columns.table_id = views.id')}` : ''} +from views` diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 8b51c721..c28ea770 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -1,18 +1 @@ -export const DEFAULT_ROLES = [ - 'pg_execute_server_program', - 'pg_monitor', - 'pg_read_all_settings', - 'pg_read_all_stats', - 'pg_read_server_files', - 'pg_signal_backend', - 'pg_stat_scan_tables', - 'pg_write_server_files', -] - -export const DEFAULT_SYSTEM_SCHEMAS = [ - 'information_schema', - 'pg_catalog', - 'pg_temp_1', - 'pg_toast', - 'pg_toast_temp_1', -] +export const DEFAULT_SYSTEM_SCHEMAS = ['information_schema', 'pg_catalog', 'pg_toast'] diff --git a/src/lib/db.ts b/src/lib/db.ts index 14fc53cf..6f7e906a 100644 --- a/src/lib/db.ts +++ b/src/lib/db.ts @@ -1,51 +1,260 @@ -import { types, Pool, PoolConfig } from 'pg' +import pg from 'pg' +import * as Sentry from '@sentry/node' import { parse as parseArray } from 'postgres-array' -import { PostgresMetaResult } from './types' - -types.setTypeParser(types.builtins.INT8, parseInt) -types.setTypeParser(types.builtins.DATE, (x) => x) -types.setTypeParser(types.builtins.TIMESTAMP, (x) => x) -types.setTypeParser(types.builtins.TIMESTAMPTZ, (x) => x) -types.setTypeParser(1115, parseArray) // _timestamp -types.setTypeParser(1182, parseArray) // _date -types.setTypeParser(1185, parseArray) // _timestamptz -types.setTypeParser(600, (x) => x) // point -types.setTypeParser(1017, (x) => x) // _point +import { PostgresMetaResult, PoolConfig } from './types.js' + +pg.types.setTypeParser(pg.types.builtins.INT8, (x) => { + const asNumber = Number(x) + if (Number.isSafeInteger(asNumber)) { + return asNumber + } else { + return x + } +}) +pg.types.setTypeParser(pg.types.builtins.DATE, (x) => x) +pg.types.setTypeParser(pg.types.builtins.INTERVAL, (x) => x) +pg.types.setTypeParser(pg.types.builtins.TIMESTAMP, (x) => x) +pg.types.setTypeParser(pg.types.builtins.TIMESTAMPTZ, (x) => x) +pg.types.setTypeParser(1115, parseArray) // _timestamp +pg.types.setTypeParser(1182, parseArray) // _date +pg.types.setTypeParser(1185, parseArray) // _timestamptz +pg.types.setTypeParser(600, (x) => x) // point +pg.types.setTypeParser(1017, (x) => x) // _point + +// Ensure any query will have an appropriate error handler on the pool to prevent connections errors +// to bubble up all the stack eventually killing the server +const poolerQueryHandleError = (pgpool: pg.Pool, sql: string): Promise> => { + return Sentry.startSpan( + { op: 'db', name: 'poolerQuery' }, + () => + new Promise((resolve, reject) => { + let rejected = false + const connectionErrorHandler = (err: any) => { + // If the error hasn't already be propagated to the catch + if (!rejected) { + // This is a trick to wait for the next tick, leaving a chance for handled errors such as + // RESULT_SIZE_LIMIT to take over other stream errors such as `unexpected commandComplete message` + setTimeout(() => { + rejected = true + return reject(err) + }) + } + } + // This listened avoid getting uncaught exceptions for errors happening at connection level within the stream + // such as parse or RESULT_SIZE_EXCEEDED errors instead, handle the error gracefully by bubbling in up to the caller + pgpool.once('error', connectionErrorHandler) + pgpool + .query(sql) + .then((results: pg.QueryResult) => { + if (!rejected) { + return resolve(results) + } + }) + .catch((err: any) => { + // If the error hasn't already be handled within the error listener + if (!rejected) { + rejected = true + return reject(err) + } + }) + }) + ) +} export const init: (config: PoolConfig) => { - query: (sql: string) => Promise> + query: ( + sql: string, + opts?: { statementQueryTimeout?: number; trackQueryInSentry?: boolean } + ) => Promise> end: () => Promise } = (config) => { - // NOTE: Race condition could happen here: one async task may be doing - // `pool.end()` which invalidates the pool and subsequently all existing - // handles to `query`. Normally you might only deal with one DB so you don't - // need to call `pool.end()`, but since the server needs this, we make a - // compromise: if we run `query` after `pool.end()` is called (i.e. pool is - // `null`), we temporarily create a pool and close it right after. - let pool: Pool | null = new Pool(config) - return { - async query(sql) { - try { - if (!pool) { - const pool = new Pool(config) - const { rows } = await pool.query(sql) - await pool.end() - return { data: rows, error: null } - } + return Sentry.startSpan({ op: 'db', name: 'db.init' }, () => { + // node-postgres ignores config.ssl if any of sslmode, sslca, sslkey, sslcert, + // sslrootcert are in the connection string. Here we allow setting sslmode in + // the connection string while setting the rest in config.ssl. + if (config.connectionString) { + const u = new URL(config.connectionString) + const sslmode = u.searchParams.get('sslmode') + u.searchParams.delete('sslmode') + // For now, we don't support setting these from the connection string. + u.searchParams.delete('sslca') + u.searchParams.delete('sslkey') + u.searchParams.delete('sslcert') + u.searchParams.delete('sslrootcert') + config.connectionString = u.toString() - const { rows } = await pool.query(sql) - return { data: rows, error: null } - } catch (e: any) { - return { data: null, error: { message: e.message } } + // sslmode: null, 'disable', 'prefer', 'require', 'verify-ca', 'verify-full', 'no-verify' + // config.ssl: true, false, {} + if (sslmode === null) { + // skip + } else if (sslmode === 'disable') { + config.ssl = false + } else { + if (typeof config.ssl !== 'object') { + config.ssl = {} + } + config.ssl.rejectUnauthorized = sslmode === 'verify-full' } - }, - - async end() { - const _pool = pool - pool = null - // Gracefully wait for active connections to be idle, then close all - // connections in the pool. - if (_pool) await _pool.end() - }, - } + } + + // NOTE: Race condition could happen here: one async task may be doing + // `pool.end()` which invalidates the pool and subsequently all existing + // handles to `query`. Normally you might only deal with one DB so you don't + // need to call `pool.end()`, but since the server needs this, we make a + // compromise: if we run `query` after `pool.end()` is called (i.e. pool is + // `null`), we temporarily create a pool and close it right after. + let pool: pg.Pool | null = new pg.Pool(config) + + return { + async query( + sql, + { statementQueryTimeout, trackQueryInSentry } = { trackQueryInSentry: true } + ) { + return Sentry.startSpan( + // For metrics purposes, log the query that will be run if it's not an user provided query (with possibly sentitives infos) + { + op: 'db', + name: 'init.query', + attributes: { sql: trackQueryInSentry ? sql : 'custom' }, + }, + async () => { + const statementTimeoutQueryPrefix = statementQueryTimeout + ? `SET statement_timeout='${statementQueryTimeout}s';` + : '' + // node-postgres need a statement_timeout to kill the connection when timeout is reached + // otherwise the query will keep running on the database even if query timeout was reached + // This need to be added at query and not connection level because poolers (pgbouncer) doesn't + // allow to set this parameter at connection time + const sqlWithStatementTimeout = `${statementTimeoutQueryPrefix}${sql}` + try { + if (!pool) { + const pool = new pg.Pool(config) + let res = await poolerQueryHandleError(pool, sqlWithStatementTimeout) + if (Array.isArray(res)) { + res = res.reverse().find((x) => x.rows.length !== 0) ?? { rows: [] } + } + await pool.end() + return { data: res.rows, error: null } + } + + let res = await poolerQueryHandleError(pool, sqlWithStatementTimeout) + if (Array.isArray(res)) { + res = res.reverse().find((x) => x.rows.length !== 0) ?? { rows: [] } + } + return { data: res.rows, error: null } + } catch (error: any) { + if (error.constructor.name === 'DatabaseError') { + // Roughly based on: + // - https://github.com/postgres/postgres/blob/fc4089f3c65a5f1b413a3299ba02b66a8e5e37d0/src/interfaces/libpq/fe-protocol3.c#L1018 + // - https://github.com/brianc/node-postgres/blob/b1a8947738ce0af004cb926f79829bb2abc64aa6/packages/pg/lib/native/query.js#L33 + let formattedError = '' + { + if (error.severity) { + formattedError += `${error.severity}: ` + } + if (error.code) { + formattedError += `${error.code}: ` + } + if (error.message) { + formattedError += error.message + } + formattedError += '\n' + if (error.position) { + // error.position is 1-based + // we also remove our `SET statement_timeout = 'XXs';\n` from the position + const position = Number(error.position) - 1 - statementTimeoutQueryPrefix.length + // we set the new error position + error.position = `${position + 1}` + + let line = '' + let lineNumber = 0 + let lineOffset = 0 + + const lines = sql.split('\n') + let currentOffset = 0 + for (let i = 0; i < lines.length; i++) { + if (currentOffset + lines[i].length > position) { + line = lines[i] + lineNumber = i + 1 // 1-based + lineOffset = position - currentOffset + break + } + currentOffset += lines[i].length + 1 // 1 extra offset for newline + } + formattedError += `LINE ${lineNumber}: ${line}\n${' '.repeat(5 + lineNumber.toString().length + 2 + lineOffset)}^\n` + } + if (error.detail) { + formattedError += `DETAIL: ${error.detail}\n` + } + if (error.hint) { + formattedError += `HINT: ${error.hint}\n` + } + if (error.internalQuery) { + formattedError += `QUERY: ${error.internalQuery}\n` + } + if (error.where) { + formattedError += `CONTEXT: ${error.where}\n` + } + } + + return { + data: null, + error: { + ...error, + // error.message is non-enumerable + message: error.message, + formattedError, + }, + } + } + try { + // Handle stream errors and result size exceeded errors + if (error.code === 'RESULT_SIZE_EXCEEDED') { + // Force kill the connection without waiting for graceful shutdown + return { + data: null, + error: { + message: `Query result size (${error.resultSize} bytes) exceeded the configured limit (${error.maxResultSize} bytes)`, + code: error.code, + resultSize: error.resultSize, + maxResultSize: error.maxResultSize, + }, + } + } + return { data: null, error: { code: error.code, message: error.message } } + } finally { + try { + // If the error isn't a "DatabaseError" assume it's a connection related we kill the connection + // To attempt a clean reconnect on next try + await this.end.bind(this) + } catch (error) { + console.error('Failed to end the connection on error: ', { + this: this, + end: this.end, + }) + } + } + } + } + ) + }, + + async end() { + Sentry.startSpan({ op: 'db', name: 'init.end' }, async () => { + try { + const _pool = pool + pool = null + // Gracefully wait for active connections to be idle, then close all + // connections in the pool. + if (_pool) { + await _pool.end() + } + } catch (endError) { + // Ignore any errors during cleanup just log them + console.error('Failed ending connection pool', endError) + } + }) + }, + } + }) } diff --git a/src/lib/generators.ts b/src/lib/generators.ts new file mode 100644 index 00000000..c916a44c --- /dev/null +++ b/src/lib/generators.ts @@ -0,0 +1,131 @@ +import PostgresMeta from './PostgresMeta.js' +import { + PostgresColumn, + PostgresForeignTable, + PostgresFunction, + PostgresMaterializedView, + PostgresMetaResult, + PostgresRelationship, + PostgresSchema, + PostgresTable, + PostgresType, + PostgresView, +} from './types.js' + +export type GeneratorMetadata = { + schemas: PostgresSchema[] + tables: Omit[] + foreignTables: Omit[] + views: Omit[] + materializedViews: Omit[] + columns: PostgresColumn[] + relationships: PostgresRelationship[] + functions: PostgresFunction[] + types: PostgresType[] +} + +export async function getGeneratorMetadata( + pgMeta: PostgresMeta, + filters: { includedSchemas?: string[]; excludedSchemas?: string[] } = { + includedSchemas: [], + excludedSchemas: [], + } +): Promise> { + const includedSchemas = filters.includedSchemas ?? [] + const excludedSchemas = filters.excludedSchemas ?? [] + + const { data: schemas, error: schemasError } = await pgMeta.schemas.list() + if (schemasError) { + return { data: null, error: schemasError } + } + + const { data: tables, error: tablesError } = await pgMeta.tables.list({ + includedSchemas: includedSchemas.length > 0 ? includedSchemas : undefined, + excludedSchemas, + includeColumns: false, + }) + if (tablesError) { + return { data: null, error: tablesError } + } + + const { data: foreignTables, error: foreignTablesError } = await pgMeta.foreignTables.list({ + includedSchemas: includedSchemas.length > 0 ? includedSchemas : undefined, + excludedSchemas, + includeColumns: false, + }) + if (foreignTablesError) { + return { data: null, error: foreignTablesError } + } + + const { data: views, error: viewsError } = await pgMeta.views.list({ + includedSchemas: includedSchemas.length > 0 ? includedSchemas : undefined, + excludedSchemas, + includeColumns: false, + }) + if (viewsError) { + return { data: null, error: viewsError } + } + + const { data: materializedViews, error: materializedViewsError } = + await pgMeta.materializedViews.list({ + includedSchemas: includedSchemas.length > 0 ? includedSchemas : undefined, + excludedSchemas, + includeColumns: false, + }) + if (materializedViewsError) { + return { data: null, error: materializedViewsError } + } + + const { data: columns, error: columnsError } = await pgMeta.columns.list({ + includedSchemas: includedSchemas.length > 0 ? includedSchemas : undefined, + excludedSchemas, + }) + if (columnsError) { + return { data: null, error: columnsError } + } + + const { data: relationships, error: relationshipsError } = await pgMeta.relationships.list() + if (relationshipsError) { + return { data: null, error: relationshipsError } + } + + const { data: functions, error: functionsError } = await pgMeta.functions.list({ + includedSchemas: includedSchemas.length > 0 ? includedSchemas : undefined, + excludedSchemas, + }) + if (functionsError) { + return { data: null, error: functionsError } + } + + const { data: types, error: typesError } = await pgMeta.types.list({ + includeTableTypes: true, + includeArrayTypes: true, + includeSystemSchemas: true, + }) + if (typesError) { + return { data: null, error: typesError } + } + + await pgMeta.end() + + return { + data: { + schemas: schemas.filter( + ({ name }) => + !excludedSchemas.includes(name) && + (includedSchemas.length === 0 || includedSchemas.includes(name)) + ), + tables, + foreignTables, + views, + materializedViews, + columns, + relationships, + functions: functions.filter( + ({ return_type }) => !['trigger', 'event_trigger'].includes(return_type) + ), + types, + }, + error: null, + } +} diff --git a/src/lib/helpers.ts b/src/lib/helpers.ts index 3d197f88..7145bb40 100644 --- a/src/lib/helpers.ts +++ b/src/lib/helpers.ts @@ -1,3 +1,5 @@ +import { literal } from 'pg-format' + export const coalesceRowsToArray = (source: string, filter: string) => { return ` COALESCE( @@ -10,3 +12,15 @@ COALESCE( '{}' ) AS ${source}` } + +export const filterByList = (include?: string[], exclude?: string[], defaultExclude?: string[]) => { + if (defaultExclude) { + exclude = defaultExclude.concat(exclude ?? []) + } + if (include?.length) { + return `IN (${include.map(literal).join(',')})` + } else if (exclude?.length) { + return `NOT IN (${exclude.map(literal).join(',')})` + } + return '' +} diff --git a/src/lib/index.ts b/src/lib/index.ts index d56c21de..246b1e71 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -1,5 +1,4 @@ -import PostgresMeta from './PostgresMeta' -export { PostgresMeta } +export { default as PostgresMeta } from './PostgresMeta.js' export { PostgresMetaOk, PostgresMetaErr, @@ -8,15 +7,20 @@ export { PostgresConfig, PostgresExtension, PostgresFunction, - PostgresGrant, + PostgresFunctionCreate, + PostgresIndex, + PostgresMaterializedView, PostgresPolicy, PostgresPrimaryKey, PostgresPublication, PostgresRelationship, PostgresRole, PostgresSchema, + PostgresSchemaCreate, + PostgresSchemaUpdate, PostgresTable, PostgresTrigger, PostgresType, PostgresVersion, -} from './types' + PostgresView, +} from './types.js' diff --git a/src/lib/secrets.ts b/src/lib/secrets.ts new file mode 100644 index 00000000..c44578ec --- /dev/null +++ b/src/lib/secrets.ts @@ -0,0 +1,24 @@ +export const getSecret = async (key: string) => { + if (!key) { + return '' + } + + const env = process.env[key] + if (env) { + return env + } + + const file = process.env[key + '_FILE'] + if (!file) { + return '' + } + // Use dynamic import to support module mock + const fs = await import('node:fs/promises') + + return await fs.readFile(file, { encoding: 'utf8' }).catch((e) => { + if (e.code == 'ENOENT') { + return '' + } + throw e + }) +} diff --git a/src/lib/sql/column_privileges.sql b/src/lib/sql/column_privileges.sql new file mode 100644 index 00000000..8540c583 --- /dev/null +++ b/src/lib/sql/column_privileges.sql @@ -0,0 +1,145 @@ +-- Lists each column's privileges in the form of: +-- +-- [ +-- { +-- "column_id": "12345.1", +-- "relation_schema": "public", +-- "relation_name": "mytable", +-- "column_name": "mycolumn", +-- "privileges": [ +-- { +-- "grantor": "postgres", +-- "grantee": "myrole", +-- "privilege_type": "SELECT", +-- "is_grantable": false +-- }, +-- ... +-- ] +-- }, +-- ... +-- ] +-- +-- Modified from information_schema.column_privileges. We try to be as close as +-- possible to the view definition, obtained from: +-- +-- select pg_get_viewdef('information_schema.column_privileges'); +-- +-- The main differences are: +-- - we include column privileges for materialized views +-- (reason for exclusion in information_schema.column_privileges: +-- https://www.postgresql.org/message-id/9136.1502740844%40sss.pgh.pa.us) +-- - we query a.attrelid and a.attnum to generate `column_id` +-- - `table_catalog` is omitted +-- - table_schema -> relation_schema, table_name -> relation_name +-- +-- Column privileges are intertwined with table privileges in that table +-- privileges override column privileges. E.g. if we do: +-- +-- grant all on mytable to myrole; +-- +-- Then `myrole` is granted privileges for ALL columns. Likewise, if we do: +-- +-- grant all (id) on mytable to myrole; +-- revoke all on mytable from myrole; +-- +-- Then the grant on the `id` column is revoked. +-- +-- This is unlike how grants for schemas and tables interact, where you need +-- privileges for BOTH the schema the table is in AND the table itself in order +-- to access the table. + +select (x.attrelid || '.' || x.attnum) as column_id, + nc.nspname as relation_schema, + x.relname as relation_name, + x.attname as column_name, + coalesce( + jsonb_agg( + jsonb_build_object( + 'grantor', u_grantor.rolname, + 'grantee', grantee.rolname, + 'privilege_type', x.prtype, + 'is_grantable', x.grantable + ) + ), + '[]' + ) as privileges +from + (select pr_c.grantor, + pr_c.grantee, + a.attrelid, + a.attnum, + a.attname, + pr_c.relname, + pr_c.relnamespace, + pr_c.prtype, + pr_c.grantable, + pr_c.relowner + from + (select pg_class.oid, + pg_class.relname, + pg_class.relnamespace, + pg_class.relowner, + (aclexplode(coalesce(pg_class.relacl, acldefault('r', pg_class.relowner)))).grantor as grantor, + (aclexplode(coalesce(pg_class.relacl, acldefault('r', pg_class.relowner)))).grantee as grantee, + (aclexplode(coalesce(pg_class.relacl, acldefault('r', pg_class.relowner)))).privilege_type as privilege_type, + (aclexplode(coalesce(pg_class.relacl, acldefault('r', pg_class.relowner)))).is_grantable as is_grantable + from pg_class + where (pg_class.relkind = any (array['r', + 'v', + 'm', + 'f', + 'p'])) ) pr_c(oid, relname, relnamespace, relowner, grantor, grantee, prtype, grantable), + pg_attribute a + where ((a.attrelid = pr_c.oid) + and (a.attnum > 0) + and (not a.attisdropped)) + union select pr_a.grantor, + pr_a.grantee, + pr_a.attrelid, + pr_a.attnum, + pr_a.attname, + c.relname, + c.relnamespace, + pr_a.prtype, + pr_a.grantable, + c.relowner + from + (select a.attrelid, + a.attnum, + a.attname, + (aclexplode(coalesce(a.attacl, acldefault('c', cc.relowner)))).grantor as grantor, + (aclexplode(coalesce(a.attacl, acldefault('c', cc.relowner)))).grantee as grantee, + (aclexplode(coalesce(a.attacl, acldefault('c', cc.relowner)))).privilege_type as privilege_type, + (aclexplode(coalesce(a.attacl, acldefault('c', cc.relowner)))).is_grantable as is_grantable + from (pg_attribute a + join pg_class cc on ((a.attrelid = cc.oid))) + where ((a.attnum > 0) + and (not a.attisdropped))) pr_a(attrelid, attnum, attname, grantor, grantee, prtype, grantable), + pg_class c + where ((pr_a.attrelid = c.oid) + and (c.relkind = any (ARRAY['r', + 'v', + 'm', + 'f', + 'p'])))) x, + pg_namespace nc, + pg_authid u_grantor, + (select pg_authid.oid, + pg_authid.rolname + from pg_authid + union all select (0)::oid as oid, + 'PUBLIC') grantee(oid, rolname) +where ((x.relnamespace = nc.oid) + and (x.grantee = grantee.oid) + and (x.grantor = u_grantor.oid) + and (x.prtype = any (ARRAY['INSERT', + 'SELECT', + 'UPDATE', + 'REFERENCES'])) + and (pg_has_role(u_grantor.oid, 'USAGE') + or pg_has_role(grantee.oid, 'USAGE') + or (grantee.rolname = 'PUBLIC'))) +group by column_id, + nc.nspname, + x.relname, + x.attname diff --git a/src/lib/sql/columns.sql b/src/lib/sql/columns.sql index b44f4384..ad01e22a 100644 --- a/src/lib/sql/columns.sql +++ b/src/lib/sql/columns.sql @@ -43,6 +43,7 @@ SELECT OR c.relkind IN ('v', 'f') AND pg_column_is_updatable(c.oid, a.attnum, FALSE) ) AS is_updatable, uniques.table_id IS NOT NULL AS is_unique, + check_constraints.definition AS "check", array_to_json( array( SELECT @@ -50,7 +51,8 @@ SELECT FROM pg_catalog.pg_enum enums WHERE - quote_ident(COALESCE(bt.typname, t.typname)) = format_type(enums.enumtypid, NULL) + enums.enumtypid = coalesce(bt.oid, t.oid) + OR enums.enumtypid = coalesce(bt.typelem, t.typelem) ORDER BY enums.enumsortorder ) @@ -74,17 +76,31 @@ FROM ) ON t.typtype = 'd' AND t.typbasetype = bt.oid LEFT JOIN ( - SELECT + SELECT DISTINCT ON (table_id, ordinal_position) conrelid AS table_id, conkey[1] AS ordinal_position FROM pg_catalog.pg_constraint WHERE contype = 'u' AND cardinality(conkey) = 1 ) AS uniques ON uniques.table_id = c.oid AND uniques.ordinal_position = a.attnum + LEFT JOIN ( + -- We only select the first column check + SELECT DISTINCT ON (table_id, ordinal_position) + conrelid AS table_id, + conkey[1] AS ordinal_position, + substring( + pg_get_constraintdef(pg_constraint.oid, true), + 8, + length(pg_get_constraintdef(pg_constraint.oid, true)) - 8 + ) AS "definition" + FROM pg_constraint + WHERE contype = 'c' AND cardinality(conkey) = 1 + ORDER BY table_id, ordinal_position, oid asc + ) AS check_constraints ON check_constraints.table_id = c.oid AND check_constraints.ordinal_position = a.attnum WHERE NOT pg_is_other_temp_schema(nc.oid) AND a.attnum > 0 AND NOT a.attisdropped - AND (c.relkind IN ('r', 'v', 'f', 'p')) + AND (c.relkind IN ('r', 'v', 'm', 'f', 'p')) AND ( pg_has_role(c.relowner, 'USAGE') OR has_column_privilege( diff --git a/src/lib/sql/foreign_tables.sql b/src/lib/sql/foreign_tables.sql new file mode 100644 index 00000000..e3e5e14f --- /dev/null +++ b/src/lib/sql/foreign_tables.sql @@ -0,0 +1,10 @@ +SELECT + c.oid :: int8 AS id, + n.nspname AS schema, + c.relname AS name, + obj_description(c.oid) AS comment +FROM + pg_class c + JOIN pg_namespace n ON n.oid = c.relnamespace +WHERE + c.relkind = 'f' diff --git a/src/lib/sql/functions.sql b/src/lib/sql/functions.sql index 47261872..d2258402 100644 --- a/src/lib/sql/functions.sql +++ b/src/lib/sql/functions.sql @@ -1,46 +1,107 @@ -SELECT - p.oid :: int8 AS id, - n.nspname AS schema, - p.proname AS name, - l.lanname AS language, - CASE - WHEN l.lanname = 'internal' THEN '' - ELSE p.prosrc - END AS definition, - CASE - WHEN l.lanname = 'internal' THEN p.prosrc - ELSE pg_get_functiondef(p.oid) - END AS complete_statement, - pg_get_function_arguments(p.oid) AS argument_types, - pg_get_function_identity_arguments(p.oid) AS identity_argument_types, - t.typname AS return_type, - CASE - WHEN p.provolatile = 'i' THEN 'IMMUTABLE' - WHEN p.provolatile = 's' THEN 'STABLE' - WHEN p.provolatile = 'v' THEN 'VOLATILE' - END AS behavior, - p.prosecdef AS security_definer, - JSON_OBJECT_AGG(p_config.param, p_config.value) - FILTER (WHERE p_config.param IS NOT NULL) AS config_params -FROM - pg_proc p - LEFT JOIN pg_namespace n ON p.pronamespace = n.oid - LEFT JOIN pg_language l ON p.prolang = l.oid - LEFT JOIN pg_type t ON t.oid = p.prorettype - LEFT JOIN ( - SELECT - oid as id, - (string_to_array(unnest(proconfig), '='))[1] AS param, - (string_to_array(unnest(proconfig), '='))[2] AS value - FROM - pg_proc - ) p_config ON p_config.id = p.oid -GROUP BY - p.oid, - n.nspname, - p.proname, - l.lanname, - p.prosrc, - t.typname, - p.provolatile, - p.prosecdef +-- CTE with sane arg_modes, arg_names, and arg_types. +-- All three are always of the same length. +-- All three include all args, including OUT and TABLE args. +with functions as ( + select + *, + -- proargmodes is null when all arg modes are IN + coalesce( + p.proargmodes, + array_fill('i'::text, array[cardinality(coalesce(p.proallargtypes, p.proargtypes))]) + ) as arg_modes, + -- proargnames is null when all args are unnamed + coalesce( + p.proargnames, + array_fill(''::text, array[cardinality(coalesce(p.proallargtypes, p.proargtypes))]) + ) as arg_names, + -- proallargtypes is null when all arg modes are IN + coalesce(p.proallargtypes, p.proargtypes) as arg_types, + array_cat( + array_fill(false, array[pronargs - pronargdefaults]), + array_fill(true, array[pronargdefaults])) as arg_has_defaults + from + pg_proc as p + where + p.prokind = 'f' +) +select + f.oid::int8 as id, + n.nspname as schema, + f.proname as name, + l.lanname as language, + case + when l.lanname = 'internal' then '' + else f.prosrc + end as definition, + case + when l.lanname = 'internal' then f.prosrc + else pg_get_functiondef(f.oid) + end as complete_statement, + coalesce(f_args.args, '[]') as args, + pg_get_function_arguments(f.oid) as argument_types, + pg_get_function_identity_arguments(f.oid) as identity_argument_types, + f.prorettype::int8 as return_type_id, + pg_get_function_result(f.oid) as return_type, + nullif(rt.typrelid::int8, 0) as return_type_relation_id, + f.proretset as is_set_returning_function, + case + when f.provolatile = 'i' then 'IMMUTABLE' + when f.provolatile = 's' then 'STABLE' + when f.provolatile = 'v' then 'VOLATILE' + end as behavior, + f.prosecdef as security_definer, + f_config.config_params as config_params +from + functions f + left join pg_namespace n on f.pronamespace = n.oid + left join pg_language l on f.prolang = l.oid + left join pg_type rt on rt.oid = f.prorettype + left join ( + select + oid, + jsonb_object_agg(param, value) filter (where param is not null) as config_params + from + ( + select + oid, + (string_to_array(unnest(proconfig), '='))[1] as param, + (string_to_array(unnest(proconfig), '='))[2] as value + from + functions + ) as t + group by + oid + ) f_config on f_config.oid = f.oid + left join ( + select + oid, + jsonb_agg(jsonb_build_object( + 'mode', t2.mode, + 'name', name, + 'type_id', type_id, + 'has_default', has_default + )) as args + from + ( + select + oid, + unnest(arg_modes) as mode, + unnest(arg_names) as name, + unnest(arg_types)::int8 as type_id, + unnest(arg_has_defaults) as has_default + from + functions + ) as t1, + lateral ( + select + case + when t1.mode = 'i' then 'in' + when t1.mode = 'o' then 'out' + when t1.mode = 'b' then 'inout' + when t1.mode = 'v' then 'variadic' + else 'table' + end as mode + ) as t2 + group by + t1.oid + ) f_args on f_args.oid = f.oid diff --git a/src/lib/sql/grants.sql b/src/lib/sql/grants.sql deleted file mode 100644 index 0a8572bc..00000000 --- a/src/lib/sql/grants.sql +++ /dev/null @@ -1,104 +0,0 @@ --- Adapted from information_schema.role_table_grants - -SELECT - c.oid :: int8 AS table_id, - u_grantor.rolname AS grantor, - grantee.rolname AS grantee, - nc.nspname AS schema, - c.relname AS table_name, - c.prtype AS privilege_type, - CASE - WHEN pg_has_role(grantee.oid, c.relowner, 'USAGE') - OR c.grantable THEN TRUE - ELSE FALSE - END AS is_grantable, - CASE - WHEN c.prtype = 'SELECT' THEN TRUE - ELSE FALSE - END AS with_hierarchy -FROM - ( - SELECT - pg_class.oid, - pg_class.relname, - pg_class.relnamespace, - pg_class.relkind, - pg_class.relowner, - ( - aclexplode( - COALESCE( - pg_class.relacl, - acldefault('r', pg_class.relowner) - ) - ) - ).grantor AS grantor, - ( - aclexplode( - COALESCE( - pg_class.relacl, - acldefault('r', pg_class.relowner) - ) - ) - ).grantee AS grantee, - ( - aclexplode( - COALESCE( - pg_class.relacl, - acldefault('r', pg_class.relowner) - ) - ) - ).privilege_type AS privilege_type, - ( - aclexplode( - COALESCE( - pg_class.relacl, - acldefault('r', pg_class.relowner) - ) - ) - ).is_grantable AS is_grantable - FROM - pg_class - ) c( - oid, - relname, - relnamespace, - relkind, - relowner, - grantor, - grantee, - prtype, - grantable - ), - pg_namespace nc, - pg_authid u_grantor, - ( - SELECT - pg_authid.oid, - pg_authid.rolname - FROM - pg_authid - UNION ALL - SELECT - 0 :: oid AS oid, - 'PUBLIC' - ) grantee(oid, rolname) -WHERE - c.relnamespace = nc.oid - AND (c.relkind IN ('r', 'v', 'f', 'p')) - AND c.grantee = grantee.oid - AND c.grantor = u_grantor.oid - AND ( - c.prtype IN ( - 'INSERT', - 'SELECT', - 'UPDATE', - 'DELETE', - 'TRUNCATE', - 'REFERENCES', - 'TRIGGER' - ) - ) - AND ( - pg_has_role(u_grantor.oid, 'USAGE') - OR pg_has_role(grantee.oid, 'USAGE') - ) diff --git a/src/lib/sql/index.ts b/src/lib/sql/index.ts index 1c44ce38..64be3aa8 100644 --- a/src/lib/sql/index.ts +++ b/src/lib/sql/index.ts @@ -1,19 +1,34 @@ -import { readFileSync } from 'fs' -import { resolve } from 'path' +import { readFile } from 'node:fs/promises' +import { dirname, join } from 'node:path' +import { fileURLToPath } from 'node:url' -export const columnsSql = readFileSync(resolve(__dirname, 'columns.sql'), 'utf-8') -export const configSql = readFileSync(resolve(__dirname, 'config.sql'), 'utf-8') -export const extensionsSql = readFileSync(resolve(__dirname, 'extensions.sql'), 'utf-8') -export const functionsSql = readFileSync(resolve(__dirname, 'functions.sql'), 'utf-8') -export const grantsSql = readFileSync(resolve(__dirname, 'grants.sql'), 'utf-8') -export const policiesSql = readFileSync(resolve(__dirname, 'policies.sql'), 'utf-8') -export const primaryKeysSql = readFileSync(resolve(__dirname, 'primary_keys.sql'), 'utf-8') -export const publicationsSql = readFileSync(resolve(__dirname, 'publications.sql'), 'utf-8') -export const relationshipsSql = readFileSync(resolve(__dirname, 'relationships.sql'), 'utf-8') -export const rolesSql = readFileSync(resolve(__dirname, 'roles.sql'), 'utf-8') -export const schemasSql = readFileSync(resolve(__dirname, 'schemas.sql'), 'utf-8') -export const tablesSql = readFileSync(resolve(__dirname, 'tables.sql'), 'utf-8') -export const triggersSql = readFileSync(resolve(__dirname, 'triggers.sql'), 'utf-8') -export const typesSql = readFileSync(resolve(__dirname, 'types.sql'), 'utf-8') -export const versionSql = readFileSync(resolve(__dirname, 'version.sql'), 'utf-8') -export const viewsSql = readFileSync(resolve(__dirname, 'views.sql'), 'utf-8') +const __dirname = dirname(fileURLToPath(import.meta.url)) +export const columnPrivilegesSql = await readFile(join(__dirname, 'column_privileges.sql'), 'utf-8') +export const columnsSql = await readFile(join(__dirname, 'columns.sql'), 'utf-8') +export const configSql = await readFile(join(__dirname, 'config.sql'), 'utf-8') +export const extensionsSql = await readFile(join(__dirname, 'extensions.sql'), 'utf-8') +export const foreignTablesSql = await readFile(join(__dirname, 'foreign_tables.sql'), 'utf-8') +export const functionsSql = await readFile(join(__dirname, 'functions.sql'), 'utf-8') +export const indexesSql = await readFile(join(__dirname, 'indexes.sql'), 'utf-8') +export const materializedViewsSql = await readFile( + join(__dirname, 'materialized_views.sql'), + 'utf-8' +) +export const policiesSql = await readFile(join(__dirname, 'policies.sql'), 'utf-8') +export const publicationsSql = await readFile(join(__dirname, 'publications.sql'), 'utf-8') +export const tableRelationshipsSql = await readFile( + join(__dirname, 'table_relationships.sql'), + 'utf-8' +) +export const rolesSql = await readFile(join(__dirname, 'roles.sql'), 'utf-8') +export const schemasSql = await readFile(join(__dirname, 'schemas.sql'), 'utf-8') +export const tablePrivilegesSql = await readFile(join(__dirname, 'table_privileges.sql'), 'utf-8') +export const tablesSql = await readFile(join(__dirname, 'tables.sql'), 'utf-8') +export const triggersSql = await readFile(join(__dirname, 'triggers.sql'), 'utf-8') +export const typesSql = await readFile(join(__dirname, 'types.sql'), 'utf-8') +export const versionSql = await readFile(join(__dirname, 'version.sql'), 'utf-8') +export const viewsKeyDependenciesSql = await readFile( + join(__dirname, 'views_key_dependencies.sql'), + 'utf-8' +) +export const viewsSql = await readFile(join(__dirname, 'views.sql'), 'utf-8') diff --git a/src/lib/sql/indexes.sql b/src/lib/sql/indexes.sql new file mode 100644 index 00000000..ff0c8f36 --- /dev/null +++ b/src/lib/sql/indexes.sql @@ -0,0 +1,41 @@ +SELECT + idx.indexrelid::int8 AS id, + idx.indrelid::int8 AS table_id, + n.nspname AS schema, + idx.indnatts AS number_of_attributes, + idx.indnkeyatts AS number_of_key_attributes, + idx.indisunique AS is_unique, + idx.indisprimary AS is_primary, + idx.indisexclusion AS is_exclusion, + idx.indimmediate AS is_immediate, + idx.indisclustered AS is_clustered, + idx.indisvalid AS is_valid, + idx.indcheckxmin AS check_xmin, + idx.indisready AS is_ready, + idx.indislive AS is_live, + idx.indisreplident AS is_replica_identity, + idx.indkey::smallint[] AS key_attributes, + idx.indcollation::integer[] AS collation, + idx.indclass::integer[] AS class, + idx.indoption::smallint[] AS options, + idx.indpred AS index_predicate, + obj_description(idx.indexrelid, 'pg_class') AS comment, + ix.indexdef as index_definition, + am.amname AS access_method, + jsonb_agg( + jsonb_build_object( + 'attribute_number', a.attnum, + 'attribute_name', a.attname, + 'data_type', format_type(a.atttypid, a.atttypmod) + ) + ORDER BY a.attnum + ) AS index_attributes + FROM + pg_index idx + JOIN pg_class c ON c.oid = idx.indexrelid + JOIN pg_namespace n ON c.relnamespace = n.oid + JOIN pg_am am ON c.relam = am.oid + JOIN pg_attribute a ON a.attrelid = c.oid AND a.attnum = ANY(idx.indkey) + JOIN pg_indexes ix ON c.relname = ix.indexname + GROUP BY + idx.indexrelid, idx.indrelid, n.nspname, idx.indnatts, idx.indnkeyatts, idx.indisunique, idx.indisprimary, idx.indisexclusion, idx.indimmediate, idx.indisclustered, idx.indisvalid, idx.indcheckxmin, idx.indisready, idx.indislive, idx.indisreplident, idx.indkey, idx.indcollation, idx.indclass, idx.indoption, idx.indexprs, idx.indpred, ix.indexdef, am.amname \ No newline at end of file diff --git a/src/lib/sql/materialized_views.sql b/src/lib/sql/materialized_views.sql new file mode 100644 index 00000000..5281f7da --- /dev/null +++ b/src/lib/sql/materialized_views.sql @@ -0,0 +1,11 @@ +select + c.oid::int8 as id, + n.nspname as schema, + c.relname as name, + c.relispopulated as is_populated, + obj_description(c.oid) as comment +from + pg_class c + join pg_namespace n on n.oid = c.relnamespace +where + c.relkind = 'm' diff --git a/src/lib/sql/policies.sql b/src/lib/sql/policies.sql index 1e92840f..20a09327 100644 --- a/src/lib/sql/policies.sql +++ b/src/lib/sql/policies.sql @@ -15,13 +15,13 @@ SELECT ELSE array_to_json( ARRAY( SELECT - pg_authid.rolname + pg_roles.rolname FROM - pg_authid + pg_roles WHERE - pg_authid.oid = ANY (pol.polroles) + pg_roles.oid = ANY (pol.polroles) ORDER BY - pg_authid.rolname + pg_roles.rolname ) ) END AS roles, diff --git a/src/lib/sql/primary_keys.sql b/src/lib/sql/primary_keys.sql deleted file mode 100644 index b49d0603..00000000 --- a/src/lib/sql/primary_keys.sql +++ /dev/null @@ -1,16 +0,0 @@ -SELECT - n.nspname AS schema, - c.relname AS table_name, - a.attname AS name, - c.oid :: int8 AS table_id -FROM - pg_index i, - pg_class c, - pg_attribute a, - pg_namespace n -WHERE - i.indrelid = c.oid - AND c.relnamespace = n.oid - AND a.attrelid = c.oid - AND a.attnum = ANY (i.indkey) - AND i.indisprimary diff --git a/src/lib/sql/publications.sql b/src/lib/sql/publications.sql index e8a925e4..ed0a2e20 100644 --- a/src/lib/sql/publications.sql +++ b/src/lib/sql/publications.sql @@ -1,7 +1,7 @@ SELECT p.oid :: int8 AS id, p.pubname AS name, - r.rolname AS owner, + p.pubowner::regrole::text AS owner, p.pubinsert AS publish_insert, p.pubupdate AS publish_update, p.pubdelete AS publish_delete, @@ -34,4 +34,3 @@ FROM WHERE pr.prpubid = p.oid ) AS pr ON 1 = 1 - JOIN pg_roles AS r ON p.pubowner = r.oid diff --git a/src/lib/sql/relationships.sql b/src/lib/sql/relationships.sql deleted file mode 100644 index 953a33e3..00000000 --- a/src/lib/sql/relationships.sql +++ /dev/null @@ -1,25 +0,0 @@ -SELECT - c.oid :: int8 AS id, - c.conname AS constraint_name, - nsa.nspname AS source_schema, - csa.relname AS source_table_name, - sa.attname AS source_column_name, - nta.nspname AS target_table_schema, - cta.relname AS target_table_name, - ta.attname AS target_column_name -FROM - pg_constraint c - JOIN ( - pg_attribute sa - JOIN pg_class csa ON sa.attrelid = csa.oid - JOIN pg_namespace nsa ON csa.relnamespace = nsa.oid - ) ON sa.attrelid = c.conrelid - AND sa.attnum = ANY (c.conkey) - JOIN ( - pg_attribute ta - JOIN pg_class cta ON ta.attrelid = cta.oid - JOIN pg_namespace nta ON cta.relnamespace = nta.oid - ) ON ta.attrelid = c.confrelid - AND ta.attnum = ANY (c.confkey) -WHERE - c.contype = 'f' diff --git a/src/lib/sql/schemas.sql b/src/lib/sql/schemas.sql index 6ba96808..a4859fff 100644 --- a/src/lib/sql/schemas.sql +++ b/src/lib/sql/schemas.sql @@ -1,15 +1,17 @@ -- Adapted from information_schema.schemata -SELECT - n.oid :: int8 AS id, - n.nspname AS name, - u.rolname AS owner -FROM +select + n.oid::int8 as id, + n.nspname as name, + u.rolname as owner +from pg_namespace n, - pg_authid u -WHERE + pg_roles u +where n.nspowner = u.oid - AND ( + and ( pg_has_role(n.nspowner, 'USAGE') - OR has_schema_privilege(n.oid, 'CREATE, USAGE') + or has_schema_privilege(n.oid, 'CREATE, USAGE') ) + and not pg_catalog.starts_with(n.nspname, 'pg_temp_') + and not pg_catalog.starts_with(n.nspname, 'pg_toast_temp_') diff --git a/src/lib/sql/table_privileges.sql b/src/lib/sql/table_privileges.sql new file mode 100644 index 00000000..435409dc --- /dev/null +++ b/src/lib/sql/table_privileges.sql @@ -0,0 +1,75 @@ +-- Despite the name `table_privileges`, this includes other kinds of relations: +-- views, matviews, etc. "Relation privileges" just doesn't roll off the tongue. +-- +-- For each relation, get its relacl in a jsonb format, +-- e.g. +-- +-- '{postgres=arwdDxt/postgres}' +-- +-- becomes +-- +-- [ +-- { +-- "grantee": "postgres", +-- "grantor": "postgres", +-- "is_grantable": false, +-- "privilege_type": "INSERT" +-- }, +-- ... +-- ] +select + c.oid as relation_id, + nc.nspname as schema, + c.relname as name, + case + when c.relkind = 'r' then 'table' + when c.relkind = 'v' then 'view' + when c.relkind = 'm' then 'materialized_view' + when c.relkind = 'f' then 'foreign_table' + when c.relkind = 'p' then 'partitioned_table' + end as kind, + coalesce( + jsonb_agg( + jsonb_build_object( + 'grantor', grantor.rolname, + 'grantee', grantee.rolname, + 'privilege_type', _priv.privilege_type, + 'is_grantable', _priv.is_grantable + ) + ) filter (where _priv is not null), + '[]' + ) as privileges +from pg_class c +join pg_namespace as nc + on nc.oid = c.relnamespace +left join lateral ( + select grantor, grantee, privilege_type, is_grantable + from aclexplode(coalesce(c.relacl, acldefault('r', c.relowner))) +) as _priv on true +left join pg_roles as grantor + on grantor.oid = _priv.grantor +left join ( + select + pg_roles.oid, + pg_roles.rolname + from pg_roles + union all + select + (0)::oid as oid, 'PUBLIC' +) as grantee (oid, rolname) + on grantee.oid = _priv.grantee +where c.relkind in ('r', 'v', 'm', 'f', 'p') + and not pg_is_other_temp_schema(c.relnamespace) + and ( + pg_has_role(c.relowner, 'USAGE') + or has_table_privilege( + c.oid, + 'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER, MAINTAIN' + ) + or has_any_column_privilege(c.oid, 'SELECT, INSERT, UPDATE, REFERENCES') + ) +group by + c.oid, + nc.nspname, + c.relname, + c.relkind diff --git a/src/lib/sql/table_relationships.sql b/src/lib/sql/table_relationships.sql new file mode 100644 index 00000000..53b80ded --- /dev/null +++ b/src/lib/sql/table_relationships.sql @@ -0,0 +1,44 @@ +-- Adapted from +-- https://github.com/PostgREST/postgrest/blob/f9f0f79fa914ac00c11fbf7f4c558e14821e67e2/src/PostgREST/SchemaCache.hs#L722 +WITH +pks_uniques_cols AS ( + SELECT + connamespace, + conrelid, + jsonb_agg(column_info.cols) as cols + FROM pg_constraint + JOIN lateral ( + SELECT array_agg(cols.attname order by cols.attnum) as cols + FROM ( select unnest(conkey) as col) _ + JOIN pg_attribute cols on cols.attrelid = conrelid and cols.attnum = col + ) column_info ON TRUE + WHERE + contype IN ('p', 'u') and + connamespace::regnamespace::text <> 'pg_catalog' + GROUP BY connamespace, conrelid +) +SELECT + traint.conname AS foreign_key_name, + ns1.nspname AS schema, + tab.relname AS relation, + column_info.cols AS columns, + ns2.nspname AS referenced_schema, + other.relname AS referenced_relation, + column_info.refs AS referenced_columns, + (column_info.cols IN (SELECT * FROM jsonb_array_elements(pks_uqs.cols))) AS is_one_to_one +FROM pg_constraint traint +JOIN LATERAL ( + SELECT + jsonb_agg(cols.attname order by ord) AS cols, + jsonb_agg(refs.attname order by ord) AS refs + FROM unnest(traint.conkey, traint.confkey) WITH ORDINALITY AS _(col, ref, ord) + JOIN pg_attribute cols ON cols.attrelid = traint.conrelid AND cols.attnum = col + JOIN pg_attribute refs ON refs.attrelid = traint.confrelid AND refs.attnum = ref +) AS column_info ON TRUE +JOIN pg_namespace ns1 ON ns1.oid = traint.connamespace +JOIN pg_class tab ON tab.oid = traint.conrelid +JOIN pg_class other ON other.oid = traint.confrelid +JOIN pg_namespace ns2 ON ns2.oid = other.relnamespace +LEFT JOIN pks_uniques_cols pks_uqs ON pks_uqs.connamespace = traint.connamespace AND pks_uqs.conrelid = traint.conrelid +WHERE traint.contype = 'f' +AND traint.conparentid = 0 diff --git a/src/lib/sql/tables.sql b/src/lib/sql/tables.sql index 5ac269fb..d0bb9df3 100644 --- a/src/lib/sql/tables.sql +++ b/src/lib/sql/tables.sql @@ -16,10 +16,67 @@ SELECT ) AS size, pg_stat_get_live_tuples(c.oid) AS live_rows_estimate, pg_stat_get_dead_tuples(c.oid) AS dead_rows_estimate, - obj_description(c.oid) AS comment + obj_description(c.oid) AS comment, + coalesce(pk.primary_keys, '[]') as primary_keys, + coalesce( + jsonb_agg(relationships) filter (where relationships is not null), + '[]' + ) as relationships FROM pg_namespace nc JOIN pg_class c ON nc.oid = c.relnamespace + left join ( + select + table_id, + jsonb_agg(_pk.*) as primary_keys + from ( + select + n.nspname as schema, + c.relname as table_name, + a.attname as name, + c.oid :: int8 as table_id + from + pg_index i, + pg_class c, + pg_attribute a, + pg_namespace n + where + i.indrelid = c.oid + and c.relnamespace = n.oid + and a.attrelid = c.oid + and a.attnum = any (i.indkey) + and i.indisprimary + ) as _pk + group by table_id + ) as pk + on pk.table_id = c.oid + left join ( + select + c.oid :: int8 as id, + c.conname as constraint_name, + nsa.nspname as source_schema, + csa.relname as source_table_name, + sa.attname as source_column_name, + nta.nspname as target_table_schema, + cta.relname as target_table_name, + ta.attname as target_column_name + from + pg_constraint c + join ( + pg_attribute sa + join pg_class csa on sa.attrelid = csa.oid + join pg_namespace nsa on csa.relnamespace = nsa.oid + ) on sa.attrelid = c.conrelid and sa.attnum = any (c.conkey) + join ( + pg_attribute ta + join pg_class cta on ta.attrelid = cta.oid + join pg_namespace nta on cta.relnamespace = nta.oid + ) on ta.attrelid = c.confrelid and ta.attnum = any (c.confkey) + where + c.contype = 'f' + ) as relationships + on (relationships.source_schema = nc.nspname and relationships.source_table_name = c.relname) + or (relationships.target_table_schema = nc.nspname and relationships.target_table_name = c.relname) WHERE c.relkind IN ('r', 'p') AND NOT pg_is_other_temp_schema(nc.oid) @@ -31,3 +88,11 @@ WHERE ) OR has_any_column_privilege(c.oid, 'SELECT, INSERT, UPDATE, REFERENCES') ) +group by + c.oid, + c.relname, + c.relrowsecurity, + c.relforcerowsecurity, + c.relreplident, + nc.nspname, + pk.primary_keys diff --git a/src/lib/sql/triggers.sql b/src/lib/sql/triggers.sql index 114d756c..09fcef14 100644 --- a/src/lib/sql/triggers.sql +++ b/src/lib/sql/triggers.sql @@ -29,6 +29,7 @@ ON pg_t.tgrelid = pg_c.oid JOIN information_schema.triggers AS is_t ON is_t.trigger_name = pg_t.tgname AND pg_c.relname = is_t.event_object_table +AND pg_c.relnamespace = (quote_ident(is_t.event_object_schema))::regnamespace JOIN pg_proc AS pg_p ON pg_t.tgfoid = pg_p.oid JOIN pg_namespace AS pg_n diff --git a/src/lib/sql/types.sql b/src/lib/sql/types.sql index ba0551d5..7a628ed1 100644 --- a/src/lib/sql/types.sql +++ b/src/lib/sql/types.sql @@ -1,42 +1,35 @@ -SELECT - t.oid :: int8 AS id, - t.typname AS name, - n.nspname AS schema, - format_type (t.oid, NULL) AS format, - array_to_json( - array( - SELECT - e.enumlabel - FROM - pg_enum e - WHERE - e.enumtypid = t.oid - ORDER BY - e.oid - ) - ) AS enums, - obj_description (t.oid, 'pg_type') AS comment -FROM +select + t.oid::int8 as id, + t.typname as name, + n.nspname as schema, + format_type (t.oid, null) as format, + coalesce(t_enums.enums, '[]') as enums, + coalesce(t_attributes.attributes, '[]') as attributes, + obj_description (t.oid, 'pg_type') as comment +from pg_type t - LEFT JOIN pg_namespace n ON n.oid = t.typnamespace -WHERE - ( - t.typrelid = 0 - OR ( - SELECT - c.relkind = 'c' - FROM - pg_class c - WHERE - c.oid = t.typrelid - ) - ) - AND NOT EXISTS ( - SELECT - 1 - FROM - pg_type el - WHERE - el.oid = t.typelem - AND el.typarray = t.oid - ) + left join pg_namespace n on n.oid = t.typnamespace + left join ( + select + enumtypid, + jsonb_agg(enumlabel order by enumsortorder) as enums + from + pg_enum + group by + enumtypid + ) as t_enums on t_enums.enumtypid = t.oid + left join ( + select + oid, + jsonb_agg( + jsonb_build_object('name', a.attname, 'type_id', a.atttypid::int8) + order by a.attnum asc + ) as attributes + from + pg_class c + join pg_attribute a on a.attrelid = c.oid + where + c.relkind = 'c' and not a.attisdropped + group by + c.oid + ) as t_attributes on t_attributes.oid = t.typrelid diff --git a/src/lib/sql/views.sql b/src/lib/sql/views.sql index d6abd43f..bd60da2b 100644 --- a/src/lib/sql/views.sql +++ b/src/lib/sql/views.sql @@ -2,6 +2,8 @@ SELECT c.oid :: int8 AS id, n.nspname AS schema, c.relname AS name, + -- See definition of information_schema.views + (pg_relation_is_updatable(c.oid, false) & 20) = 20 AS is_updatable, obj_description(c.oid) AS comment FROM pg_class c diff --git a/src/lib/sql/views_key_dependencies.sql b/src/lib/sql/views_key_dependencies.sql new file mode 100644 index 00000000..c8534486 --- /dev/null +++ b/src/lib/sql/views_key_dependencies.sql @@ -0,0 +1,191 @@ +-- Adapted from +-- https://github.com/PostgREST/postgrest/blob/f9f0f79fa914ac00c11fbf7f4c558e14821e67e2/src/PostgREST/SchemaCache.hs#L820 +with recursive +pks_fks as ( + -- pk + fk referencing col + select + contype::text as contype, + conname, + array_length(conkey, 1) as ncol, + conrelid as resorigtbl, + col as resorigcol, + ord + from pg_constraint + left join lateral unnest(conkey) with ordinality as _(col, ord) on true + where contype IN ('p', 'f') + union + -- fk referenced col + select + concat(contype, '_ref') as contype, + conname, + array_length(confkey, 1) as ncol, + confrelid, + col, + ord + from pg_constraint + left join lateral unnest(confkey) with ordinality as _(col, ord) on true + where contype='f' +), +views as ( + select + c.oid as view_id, + n.nspname as view_schema, + c.relname as view_name, + r.ev_action as view_definition + from pg_class c + join pg_namespace n on n.oid = c.relnamespace + join pg_rewrite r on r.ev_class = c.oid + where c.relkind in ('v', 'm') and n.nspname not in (__EXCLUDED_SCHEMAS) +), +transform_json as ( + select + view_id, view_schema, view_name, + -- the following formatting is without indentation on purpose + -- to allow simple diffs, with less whitespace noise + replace( + replace( + replace( + replace( + replace( + replace( + replace( + regexp_replace( + replace( + replace( + replace( + replace( + replace( + replace( + replace( + replace( + replace( + replace( + replace( + view_definition::text, + -- This conversion to json is heavily optimized for performance. + -- The general idea is to use as few regexp_replace() calls as possible. + -- Simple replace() is a lot faster, so we jump through some hoops + -- to be able to use regexp_replace() only once. + -- This has been tested against a huge schema with 250+ different views. + -- The unit tests do NOT reflect all possible inputs. Be careful when changing this! + -- ----------------------------------------------- + -- pattern | replacement | flags + -- ----------------------------------------------- + -- `<>` in pg_node_tree is the same as `null` in JSON, but due to very poor performance of json_typeof + -- we need to make this an empty array here to prevent json_array_elements from throwing an error + -- when the targetList is null. + -- We'll need to put it first, to make the node protection below work for node lists that start with + -- null: `(<> ...`, too. This is the case for coldefexprs, when the first column does not have a default value. + '<>' , '()' + -- `,` is not part of the pg_node_tree format, but used in the regex. + -- This removes all `,` that might be part of column names. + ), ',' , '' + -- The same applies for `{` and `}`, although those are used a lot in pg_node_tree. + -- We remove the escaped ones, which might be part of column names again. + ), E'\\{' , '' + ), E'\\}' , '' + -- The fields we need are formatted as json manually to protect them from the regex. + ), ' :targetList ' , ',"targetList":' + ), ' :resno ' , ',"resno":' + ), ' :resorigtbl ' , ',"resorigtbl":' + ), ' :resorigcol ' , ',"resorigcol":' + -- Make the regex also match the node type, e.g. `{QUERY ...`, to remove it in one pass. + ), '{' , '{ :' + -- Protect node lists, which start with `({` or `((` from the greedy regex. + -- The extra `{` is removed again later. + ), '((' , '{((' + ), '({' , '{({' + -- This regex removes all unused fields to avoid the need to format all of them correctly. + -- This leads to a smaller json result as well. + -- Removal stops at `,` for used fields (see above) and `}` for the end of the current node. + -- Nesting can't be parsed correctly with a regex, so we stop at `{` as well and + -- add an empty key for the followig node. + ), ' :[^}{,]+' , ',"":' , 'g' + -- For performance, the regex also added those empty keys when hitting a `,` or `}`. + -- Those are removed next. + ), ',"":}' , '}' + ), ',"":,' , ',' + -- This reverses the "node list protection" from above. + ), '{(' , '(' + -- Every key above has been added with a `,` so far. The first key in an object doesn't need it. + ), '{,' , '{' + -- pg_node_tree has `()` around lists, but JSON uses `[]` + ), '(' , '[' + ), ')' , ']' + -- pg_node_tree has ` ` between list items, but JSON uses `,` + ), ' ' , ',' + )::json as view_definition + from views +), +target_entries as( + select + view_id, view_schema, view_name, + json_array_elements(view_definition->0->'targetList') as entry + from transform_json +), +results as( + select + view_id, view_schema, view_name, + (entry->>'resno')::int as view_column, + (entry->>'resorigtbl')::oid as resorigtbl, + (entry->>'resorigcol')::int as resorigcol + from target_entries +), +-- CYCLE detection according to PG docs: https://www.postgresql.org/docs/current/queries-with.html#QUERIES-WITH-CYCLE +-- Can be replaced with CYCLE clause once PG v13 is EOL. +recursion(view_id, view_schema, view_name, view_column, resorigtbl, resorigcol, is_cycle, path) as( + select + r.*, + false, + ARRAY[resorigtbl] + from results r + where view_schema not in (__EXCLUDED_SCHEMAS) + union all + select + view.view_id, + view.view_schema, + view.view_name, + view.view_column, + tab.resorigtbl, + tab.resorigcol, + tab.resorigtbl = ANY(path), + path || tab.resorigtbl + from recursion view + join results tab on view.resorigtbl=tab.view_id and view.resorigcol=tab.view_column + where not is_cycle +), +repeated_references as( + select + view_id, + view_schema, + view_name, + resorigtbl, + resorigcol, + array_agg(attname) as view_columns + from recursion + join pg_attribute vcol on vcol.attrelid = view_id and vcol.attnum = view_column + group by + view_id, + view_schema, + view_name, + resorigtbl, + resorigcol +) +select + sch.nspname as table_schema, + tbl.relname as table_name, + rep.view_schema, + rep.view_name, + pks_fks.conname as constraint_name, + pks_fks.contype as constraint_type, + jsonb_agg( + jsonb_build_object('table_column', col.attname, 'view_columns', view_columns) order by pks_fks.ord + ) as column_dependencies +from repeated_references rep +join pks_fks using (resorigtbl, resorigcol) +join pg_class tbl on tbl.oid = rep.resorigtbl +join pg_attribute col on col.attrelid = tbl.oid and col.attnum = rep.resorigcol +join pg_namespace sch on sch.oid = tbl.relnamespace +group by sch.nspname, tbl.relname, rep.view_schema, rep.view_name, pks_fks.conname, pks_fks.contype, pks_fks.ncol +-- make sure we only return key for which all columns are referenced in the view - no partial PKs or FKs +having ncol = array_length(array_agg(row(col.attname, view_columns) order by pks_fks.ord), 1) diff --git a/src/lib/types.ts b/src/lib/types.ts index 815eb796..bfd60250 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -1,5 +1,7 @@ import { Static, Type } from '@sinclair/typebox' -import { Options as PrettierOptions } from 'prettier' +import { DatabaseError } from 'pg-protocol' +import type { Options as PrettierOptions } from 'prettier' +import { PoolConfig as PgPoolConfig } from 'pg' export interface FormatterOptions extends PrettierOptions {} @@ -10,9 +12,7 @@ export interface PostgresMetaOk { export interface PostgresMetaErr { data: null - error: { - message: string - } + error: Partial & { message: string; formattedError?: string } } export type PostgresMetaResult = PostgresMetaOk | PostgresMetaErr @@ -21,7 +21,7 @@ export const postgresColumnSchema = Type.Object({ table_id: Type.Integer(), schema: Type.String(), table: Type.String(), - id: Type.RegEx(/^(\d+)\.(\d+)$/), + id: Type.RegExp(/^(\d+)\.(\d+)$/), ordinal_position: Type.Integer(), name: Type.String(), default_value: Type.Unknown(), @@ -37,11 +37,56 @@ export const postgresColumnSchema = Type.Object({ is_nullable: Type.Boolean(), is_updatable: Type.Boolean(), is_unique: Type.Boolean(), - enums: Type.Array(Type.Unknown()), + enums: Type.Array(Type.String()), + check: Type.Union([Type.String(), Type.Null()]), comment: Type.Union([Type.String(), Type.Null()]), }) export type PostgresColumn = Static +export const postgresColumnCreateSchema = Type.Object({ + table_id: Type.Integer(), + name: Type.String(), + type: Type.String(), + default_value: Type.Optional(Type.Unknown()), + default_value_format: Type.Optional( + Type.Union([Type.Literal('expression'), Type.Literal('literal')]) + ), + is_identity: Type.Optional(Type.Boolean()), + identity_generation: Type.Optional( + Type.Union([Type.Literal('BY DEFAULT'), Type.Literal('ALWAYS')]) + ), + is_nullable: Type.Optional(Type.Boolean()), + is_primary_key: Type.Optional(Type.Boolean()), + is_unique: Type.Optional(Type.Boolean()), + comment: Type.Optional(Type.String()), + check: Type.Optional(Type.String()), +}) +export type PostgresColumnCreate = Static + +export const postgresColumnUpdateSchema = Type.Object({ + name: Type.Optional(Type.String()), + type: Type.Optional(Type.String()), + drop_default: Type.Optional(Type.Boolean()), + default_value: Type.Optional(Type.Unknown()), + default_value_format: Type.Optional( + Type.Union([Type.Literal('expression'), Type.Literal('literal')]) + ), + is_identity: Type.Optional(Type.Boolean()), + identity_generation: Type.Optional( + Type.Union([Type.Literal('BY DEFAULT'), Type.Literal('ALWAYS')]) + ), + is_nullable: Type.Optional(Type.Boolean()), + is_unique: Type.Optional(Type.Boolean()), + comment: Type.Optional(Type.String()), + check: Type.Optional( + Type.Union( + // Type.Null() must go first: https://github.com/sinclairzx81/typebox/issues/546 + [Type.Null(), Type.String()] + ) + ), +}) +export type PostgresColumnUpdate = Static + // TODO Rethink config.sql export const postgresConfigSchema = Type.Object({ name: Type.Unknown(), @@ -75,6 +120,15 @@ export const postgresExtensionSchema = Type.Object({ }) export type PostgresExtension = Static +export const postgresForeignTableSchema = Type.Object({ + id: Type.Integer(), + schema: Type.String(), + name: Type.String(), + comment: Type.Union([Type.String(), Type.Null()]), + columns: Type.Optional(Type.Array(postgresColumnSchema)), +}) +export type PostgresForeignTable = Static + const postgresFunctionSchema = Type.Object({ id: Type.Integer(), schema: Type.String(), @@ -82,9 +136,26 @@ const postgresFunctionSchema = Type.Object({ language: Type.String(), definition: Type.String(), complete_statement: Type.String(), + args: Type.Array( + Type.Object({ + mode: Type.Union([ + Type.Literal('in'), + Type.Literal('out'), + Type.Literal('inout'), + Type.Literal('variadic'), + Type.Literal('table'), + ]), + name: Type.String(), + type_id: Type.Number(), + has_default: Type.Boolean(), + }) + ), argument_types: Type.String(), identity_argument_types: Type.String(), + return_type_id: Type.Integer(), return_type: Type.String(), + return_type_relation_id: Type.Union([Type.Integer(), Type.Null()]), + is_set_returning_function: Type.Boolean(), behavior: Type.Union([ Type.Literal('IMMUTABLE'), Type.Literal('STABLE'), @@ -110,25 +181,39 @@ export const postgresFunctionCreateFunction = Type.Object({ }) export type PostgresFunctionCreate = Static -export const postgresGrantSchema = Type.Object({ +const postgresIndexSchema = Type.Object({ + id: Type.Integer(), table_id: Type.Integer(), - grantor: Type.String(), - grantee: Type.String(), schema: Type.String(), - table_name: Type.String(), - privilege_type: Type.Union([ - Type.Literal('INSERT'), - Type.Literal('SELECT'), - Type.Literal('UPDATE'), - Type.Literal('DELETE'), - Type.Literal('TRUNCATE'), - Type.Literal('REFERENCES'), - Type.Literal('TRIGGER'), - ]), - is_grantable: Type.Boolean(), - with_hierarchy: Type.Boolean(), + number_of_attributes: Type.Integer(), + number_of_key_attributes: Type.Integer(), + is_unique: Type.Boolean(), + is_primary: Type.Boolean(), + is_exclusion: Type.Boolean(), + is_immediate: Type.Boolean(), + is_clustered: Type.Boolean(), + is_valid: Type.Boolean(), + check_xmin: Type.Boolean(), + is_ready: Type.Boolean(), + is_live: Type.Boolean(), + is_replica_identity: Type.Boolean(), + key_attributes: Type.Array(Type.Number()), + collation: Type.Array(Type.Number()), + class: Type.Array(Type.Number()), + options: Type.Array(Type.Number()), + index_predicate: Type.Union([Type.String(), Type.Null()]), + comment: Type.Union([Type.String(), Type.Null()]), + index_definition: Type.String(), + access_method: Type.String(), + index_attributes: Type.Array( + Type.Object({ + attribute_number: Type.Number(), + attribute_name: Type.String(), + data_type: Type.String(), + }) + ), }) -export type PostgresGrant = Static +export type PostgresIndex = Static export const postgresPolicySchema = Type.Object({ id: Type.Integer(), @@ -167,19 +252,13 @@ export const postgresPublicationSchema = Type.Object({ publish_delete: Type.Boolean(), publish_truncate: Type.Boolean(), tables: Type.Union([ - Type.Array( - Type.Object({ - id: Type.Integer(), - name: Type.String(), - schema: Type.String(), - }) - ), + Type.Array(Type.Object({ id: Type.Integer(), name: Type.String(), schema: Type.String() })), Type.Null(), ]), }) export type PostgresPublication = Static -export const postgresRelationshipSchema = Type.Object({ +export const postgresRelationshipOldSchema = Type.Object({ id: Type.Integer(), constraint_name: Type.String(), source_schema: Type.String(), @@ -189,8 +268,25 @@ export const postgresRelationshipSchema = Type.Object({ target_table_name: Type.String(), target_column_name: Type.String(), }) +export const postgresRelationshipSchema = Type.Object({ + foreign_key_name: Type.String(), + schema: Type.String(), + relation: Type.String(), + columns: Type.Array(Type.String()), + is_one_to_one: Type.Boolean(), + referenced_schema: Type.String(), + referenced_relation: Type.String(), + referenced_columns: Type.Array(Type.String()), +}) export type PostgresRelationship = Static +export const PostgresMetaRoleConfigSchema = Type.Object({ + op: Type.Union([Type.Literal('remove'), Type.Literal('add'), Type.Literal('replace')]), + path: Type.String(), + value: Type.Optional(Type.String()), +}) +export type PostgresMetaRoleConfig = Static + export const postgresRoleSchema = Type.Object({ id: Type.Integer(), name: Type.String(), @@ -205,11 +301,45 @@ export const postgresRoleSchema = Type.Object({ connection_limit: Type.Integer(), password: Type.String(), valid_until: Type.Union([Type.String(), Type.Null()]), - config: Type.Union([Type.String(), Type.Null()]), - grants: Type.Array(postgresGrantSchema), + config: Type.Union([Type.String(), Type.Null(), Type.Record(Type.String(), Type.String())]), }) export type PostgresRole = Static +export const postgresRoleCreateSchema = Type.Object({ + name: Type.String(), + password: Type.Optional(Type.String()), + inherit_role: Type.Optional(Type.Boolean()), + can_login: Type.Optional(Type.Boolean()), + is_superuser: Type.Optional(Type.Boolean()), + can_create_db: Type.Optional(Type.Boolean()), + can_create_role: Type.Optional(Type.Boolean()), + is_replication_role: Type.Optional(Type.Boolean()), + can_bypass_rls: Type.Optional(Type.Boolean()), + connection_limit: Type.Optional(Type.Integer()), + member_of: Type.Optional(Type.Array(Type.String())), + members: Type.Optional(Type.Array(Type.String())), + admins: Type.Optional(Type.Array(Type.String())), + valid_until: Type.Optional(Type.String()), + config: Type.Optional(Type.Record(Type.String(), Type.String())), +}) +export type PostgresRoleCreate = Static + +export const postgresRoleUpdateSchema = Type.Object({ + name: Type.Optional(Type.String()), + password: Type.Optional(Type.String()), + inherit_role: Type.Optional(Type.Boolean()), + can_login: Type.Optional(Type.Boolean()), + is_superuser: Type.Optional(Type.Boolean()), + can_create_db: Type.Optional(Type.Boolean()), + can_create_role: Type.Optional(Type.Boolean()), + is_replication_role: Type.Optional(Type.Boolean()), + can_bypass_rls: Type.Optional(Type.Boolean()), + connection_limit: Type.Optional(Type.Integer()), + valid_until: Type.Optional(Type.String()), + config: Type.Optional(Type.Array(PostgresMetaRoleConfigSchema)), +}) +export type PostgresRoleUpdate = Static + export const postgresSchemaSchema = Type.Object({ id: Type.Integer(), name: Type.String(), @@ -246,14 +376,38 @@ export const postgresTableSchema = Type.Object({ live_rows_estimate: Type.Integer(), dead_rows_estimate: Type.Integer(), comment: Type.Union([Type.String(), Type.Null()]), - columns: Type.Array(postgresColumnSchema), - grants: Type.Array(postgresGrantSchema), - policies: Type.Array(postgresPolicySchema), + columns: Type.Optional(Type.Array(postgresColumnSchema)), primary_keys: Type.Array(postgresPrimaryKeySchema), - relationships: Type.Array(postgresRelationshipSchema), + relationships: Type.Array(postgresRelationshipOldSchema), }) export type PostgresTable = Static +export const postgresTableCreateSchema = Type.Object({ + name: Type.String(), + schema: Type.Optional(Type.String()), + comment: Type.Optional(Type.String()), +}) +export type PostgresTableCreate = Static + +export const postgresTableUpdateSchema = Type.Object({ + name: Type.Optional(Type.String()), + schema: Type.Optional(Type.String()), + rls_enabled: Type.Optional(Type.Boolean()), + rls_forced: Type.Optional(Type.Boolean()), + replica_identity: Type.Optional( + Type.Union([ + Type.Literal('DEFAULT'), + Type.Literal('INDEX'), + Type.Literal('FULL'), + Type.Literal('NOTHING'), + ]) + ), + replica_identity_index: Type.Optional(Type.String()), + primary_keys: Type.Optional(Type.Array(Type.Object({ name: Type.String() }))), + comment: Type.Optional(Type.String()), +}) +export type PostgresTableUpdate = Static + export const postgresTriggerSchema = Type.Object({ id: Type.Integer(), table_id: Type.Integer(), @@ -285,7 +439,8 @@ export const postgresTypeSchema = Type.Object({ name: Type.String(), schema: Type.String(), format: Type.String(), - enums: Type.Array(Type.Unknown()), + enums: Type.Array(Type.String()), + attributes: Type.Array(Type.Object({ name: Type.String(), type_id: Type.Integer() })), comment: Type.Union([Type.String(), Type.Null()]), }) export type PostgresType = Static @@ -302,6 +457,136 @@ export const postgresViewSchema = Type.Object({ id: Type.Integer(), schema: Type.String(), name: Type.String(), + is_updatable: Type.Boolean(), comment: Type.Union([Type.String(), Type.Null()]), + columns: Type.Optional(Type.Array(postgresColumnSchema)), }) export type PostgresView = Static + +export const postgresMaterializedViewSchema = Type.Object({ + id: Type.Integer(), + schema: Type.String(), + name: Type.String(), + is_populated: Type.Boolean(), + comment: Type.Union([Type.String(), Type.Null()]), + columns: Type.Optional(Type.Array(postgresColumnSchema)), +}) +export type PostgresMaterializedView = Static + +export const postgresTablePrivilegesSchema = Type.Object({ + relation_id: Type.Integer(), + schema: Type.String(), + name: Type.String(), + kind: Type.Union([ + Type.Literal('table'), + Type.Literal('view'), + Type.Literal('materialized_view'), + Type.Literal('foreign_table'), + Type.Literal('partitioned_table'), + ]), + privileges: Type.Array( + Type.Object({ + grantor: Type.String(), + grantee: Type.String(), + privilege_type: Type.Union([ + Type.Literal('SELECT'), + Type.Literal('INSERT'), + Type.Literal('UPDATE'), + Type.Literal('DELETE'), + Type.Literal('TRUNCATE'), + Type.Literal('REFERENCES'), + Type.Literal('TRIGGER'), + Type.Literal('MAINTAIN'), + ]), + is_grantable: Type.Boolean(), + }) + ), +}) +export type PostgresTablePrivileges = Static + +export const postgresTablePrivilegesGrantSchema = Type.Object({ + relation_id: Type.Integer(), + grantee: Type.String(), + privilege_type: Type.Union([ + Type.Literal('ALL'), + Type.Literal('SELECT'), + Type.Literal('INSERT'), + Type.Literal('UPDATE'), + Type.Literal('DELETE'), + Type.Literal('TRUNCATE'), + Type.Literal('REFERENCES'), + Type.Literal('TRIGGER'), + Type.Literal('MAINTAIN'), + ]), + is_grantable: Type.Optional(Type.Boolean()), +}) +export type PostgresTablePrivilegesGrant = Static + +export const postgresTablePrivilegesRevokeSchema = Type.Object({ + relation_id: Type.Integer(), + grantee: Type.String(), + privilege_type: Type.Union([ + Type.Literal('ALL'), + Type.Literal('SELECT'), + Type.Literal('INSERT'), + Type.Literal('UPDATE'), + Type.Literal('DELETE'), + Type.Literal('TRUNCATE'), + Type.Literal('REFERENCES'), + Type.Literal('TRIGGER'), + Type.Literal('MAINTAIN'), + ]), +}) +export type PostgresTablePrivilegesRevoke = Static + +export const postgresColumnPrivilegesSchema = Type.Object({ + column_id: Type.RegExp(/^(\d+)\.(\d+)$/), + relation_schema: Type.String(), + relation_name: Type.String(), + column_name: Type.String(), + privileges: Type.Array( + Type.Object({ + grantor: Type.String(), + grantee: Type.String(), + privilege_type: Type.Union([ + Type.Literal('SELECT'), + Type.Literal('INSERT'), + Type.Literal('UPDATE'), + Type.Literal('REFERENCES'), + ]), + is_grantable: Type.Boolean(), + }) + ), +}) +export type PostgresColumnPrivileges = Static + +export const postgresColumnPrivilegesGrantSchema = Type.Object({ + column_id: Type.RegExp(/^(\d+)\.(\d+)$/), + grantee: Type.String(), + privilege_type: Type.Union([ + Type.Literal('ALL'), + Type.Literal('SELECT'), + Type.Literal('INSERT'), + Type.Literal('UPDATE'), + Type.Literal('REFERENCES'), + ]), + is_grantable: Type.Optional(Type.Boolean()), +}) +export type PostgresColumnPrivilegesGrant = Static + +export const postgresColumnPrivilegesRevokeSchema = Type.Object({ + column_id: Type.RegExp(/^(\d+)\.(\d+)$/), + grantee: Type.String(), + privilege_type: Type.Union([ + Type.Literal('ALL'), + Type.Literal('SELECT'), + Type.Literal('INSERT'), + Type.Literal('UPDATE'), + Type.Literal('REFERENCES'), + ]), +}) +export type PostgresColumnPrivilegesRevoke = Static + +export interface PoolConfig extends PgPoolConfig { + maxResultSize?: number +} diff --git a/src/server/admin-app.ts b/src/server/admin-app.ts new file mode 100644 index 00000000..4d6595e7 --- /dev/null +++ b/src/server/admin-app.ts @@ -0,0 +1,14 @@ +import './sentry.js' +import * as Sentry from '@sentry/node' +import { fastify, FastifyInstance, FastifyServerOptions } from 'fastify' +import fastifyMetrics from 'fastify-metrics' + +export function build(opts: FastifyServerOptions = {}): FastifyInstance { + const app = fastify(opts) + Sentry.setupFastifyErrorHandler(app) + app.register(fastifyMetrics.default, { + endpoint: '/metrics', + routeMetrics: { enabled: false }, + }) + return app +} diff --git a/src/server/app.ts b/src/server/app.ts index 1eac0c06..8efa733c 100644 --- a/src/server/app.ts +++ b/src/server/app.ts @@ -1,37 +1,29 @@ -import fastify from 'fastify' -import { PG_META_EXPORT_DOCS, PG_META_PORT, PG_META_REQ_HEADER } from './constants' -import routes from './routes' -import { extractRequestForLogging } from './utils' -import pino from 'pino' -import pkg from '../../package.json' - -const logger = pino({ - formatters: { - level(label) { - return { level: label } - }, - }, - timestamp: pino.stdTimeFunctions.isoTime, -}) - -const app = fastify({ - logger, - disableRequestLogging: true, - requestIdHeader: PG_META_REQ_HEADER, -}) - -app.setErrorHandler((error, request, reply) => { - app.log.error({ error: error.toString(), request: extractRequestForLogging(request) }) - reply.code(500).send({ error: error.message }) -}) +import './sentry.js' +import * as Sentry from '@sentry/node' +import cors from '@fastify/cors' +import swagger from '@fastify/swagger' +import { fastify, FastifyInstance, FastifyServerOptions } from 'fastify' +import { PG_META_REQ_HEADER } from './constants.js' +import routes from './routes/index.js' +import { extractRequestForLogging } from './utils.js' +// Pseudo package declared only for this module +import pkg from '#package.json' with { type: 'json' } + +export const build = (opts: FastifyServerOptions = {}): FastifyInstance => { + const app = fastify({ disableRequestLogging: true, requestIdHeader: PG_META_REQ_HEADER, ...opts }) + Sentry.setupFastifyErrorHandler(app) + + app.setErrorHandler((error, request, reply) => { + app.log.error({ error: error.toString(), request: extractRequestForLogging(request) }) + reply.code(500).send({ error: error.message }) + }) -app.setNotFoundHandler((request, reply) => { - app.log.error({ error: 'Not found', request: extractRequestForLogging(request) }) - reply.code(404).send({ error: 'Not found' }) -}) + app.setNotFoundHandler((request, reply) => { + app.log.error({ error: 'Not found', request: extractRequestForLogging(request) }) + reply.code(404).send({ error: 'Not found' }) + }) -if (PG_META_EXPORT_DOCS) { - app.register(require('fastify-swagger'), { + app.register(swagger, { openapi: { servers: [], info: { @@ -42,38 +34,22 @@ if (PG_META_EXPORT_DOCS) { }, }) - app.ready(() => { - require('fs').writeFileSync( - 'openapi.json', - JSON.stringify( - // @ts-ignore: app.swagger() is a Fastify decorator, so doesn't show up in the types - app.swagger(), - null, - 2 - ) + '\n' - ) - }) -} else { - app.ready(() => { - app.listen(PG_META_PORT, '0.0.0.0', () => { - app.log.info(`App started on port ${PG_META_PORT}`) - }) - }) -} + app.register(cors) -app.register(require('fastify-cors')) + app.get('/', async (_request, _reply) => { + return { + status: 200, + name: pkg.name, + version: pkg.version, + documentation: 'https://github.com/supabase/postgres-meta', + } + }) -app.get('/', async (_request, _reply) => { - return { - status: 200, - name: pkg.name, - version: pkg.version, - documentation: 'https://github.com/supabase/postgres-meta', - } -}) + app.get('/health', async (_request, _reply) => { + return { date: new Date() } + }) -app.get('/health', async (_request, _reply) => { - return { date: new Date() } -}) + app.register(routes) -app.register(routes) + return app +} diff --git a/src/server/constants.ts b/src/server/constants.ts index cf9717b7..4d1965f9 100644 --- a/src/server/constants.ts +++ b/src/server/constants.ts @@ -1,17 +1,68 @@ +import crypto from 'crypto' +import { PoolConfig } from '../lib/types.js' +import { getSecret } from '../lib/secrets.js' +import { AccessControl } from './templates/swift.js' +import pkg from '#package.json' with { type: 'json' } + +export const PG_META_HOST = process.env.PG_META_HOST || '0.0.0.0' export const PG_META_PORT = Number(process.env.PG_META_PORT || 1337) -export const CRYPTO_KEY = process.env.CRYPTO_KEY || 'SAMPLE_KEY' +export const CRYPTO_KEY = (await getSecret('CRYPTO_KEY')) || 'SAMPLE_KEY' const PG_META_DB_HOST = process.env.PG_META_DB_HOST || 'localhost' const PG_META_DB_NAME = process.env.PG_META_DB_NAME || 'postgres' const PG_META_DB_USER = process.env.PG_META_DB_USER || 'postgres' -const PG_META_DB_PORT = Number(process.env.PG_META_DB_PORT) || 5432 -const PG_META_DB_PASSWORD = process.env.PG_META_DB_PASSWORD || 'postgres' +const PG_META_DB_PORT = process.env.PG_META_DB_PORT || '5432' +const PG_META_DB_PASSWORD = (await getSecret('PG_META_DB_PASSWORD')) || 'postgres' +const PG_META_DB_SSL_MODE = process.env.PG_META_DB_SSL_MODE || 'disable' const PG_CONN_TIMEOUT_SECS = Number(process.env.PG_CONN_TIMEOUT_SECS || 15) +const PG_QUERY_TIMEOUT_SECS = Number(process.env.PG_QUERY_TIMEOUT_SECS || 55) + +export let PG_CONNECTION = process.env.PG_META_DB_URL +if (!PG_CONNECTION) { + const pgConn = new URL('postgresql://') + pgConn.hostname = PG_META_DB_HOST + pgConn.port = PG_META_DB_PORT + pgConn.username = PG_META_DB_USER + pgConn.password = PG_META_DB_PASSWORD + pgConn.pathname = encodeURIComponent(PG_META_DB_NAME) + pgConn.searchParams.set('sslmode', PG_META_DB_SSL_MODE) + PG_CONNECTION = `${pgConn}` +} + +export const PG_META_DB_SSL_ROOT_CERT = process.env.PG_META_DB_SSL_ROOT_CERT +if (PG_META_DB_SSL_ROOT_CERT) { + // validate cert + new crypto.X509Certificate(PG_META_DB_SSL_ROOT_CERT) +} + +export const EXPORT_DOCS = process.env.PG_META_EXPORT_DOCS === 'true' +export const GENERATE_TYPES = process.env.PG_META_GENERATE_TYPES +export const GENERATE_TYPES_INCLUDED_SCHEMAS = GENERATE_TYPES + ? (process.env.PG_META_GENERATE_TYPES_INCLUDED_SCHEMAS?.split(',') ?? []) + : [] +export const GENERATE_TYPES_DEFAULT_SCHEMA = + process.env.PG_META_GENERATE_TYPES_DEFAULT_SCHEMA || 'public' +export const GENERATE_TYPES_DETECT_ONE_TO_ONE_RELATIONSHIPS = + process.env.PG_META_GENERATE_TYPES_DETECT_ONE_TO_ONE_RELATIONSHIPS === 'true' +export const GENERATE_TYPES_SWIFT_ACCESS_CONTROL = process.env + .PG_META_GENERATE_TYPES_SWIFT_ACCESS_CONTROL + ? (process.env.PG_META_GENERATE_TYPES_SWIFT_ACCESS_CONTROL as AccessControl) + : 'internal' -export const PG_CONNECTION = `postgres://${PG_META_DB_USER}:${PG_META_DB_PASSWORD}@${PG_META_DB_HOST}:${PG_META_DB_PORT}/${PG_META_DB_NAME}?sslmode=disable` +export const PG_META_MAX_RESULT_SIZE = process.env.PG_META_MAX_RESULT_SIZE_MB + ? // Node-postgres get a maximum size in bytes make the conversion from the env variable + // from MB to Bytes + parseInt(process.env.PG_META_MAX_RESULT_SIZE_MB, 10) * 1024 * 1024 + : 2 * 1024 * 1024 * 1024 // default to 2GB max query size result -export const PG_META_EXPORT_DOCS = process.env.PG_META_EXPORT_DOCS === 'true' || false +export const DEFAULT_POOL_CONFIG: PoolConfig = { + max: 1, + connectionTimeoutMillis: PG_CONN_TIMEOUT_SECS * 1000, + query_timeout: PG_QUERY_TIMEOUT_SECS * 1000, + ssl: PG_META_DB_SSL_ROOT_CERT ? { ca: PG_META_DB_SSL_ROOT_CERT } : undefined, + application_name: `postgres-meta ${pkg.version}`, + maxResultSize: PG_META_MAX_RESULT_SIZE, +} -export const DEFAULT_POOL_CONFIG = { max: 1, connectionTimeoutMillis: PG_CONN_TIMEOUT_SECS * 1000 } export const PG_META_REQ_HEADER = process.env.PG_META_REQ_HEADER || 'request-id' diff --git a/src/server/routes/column-privileges.ts b/src/server/routes/column-privileges.ts new file mode 100644 index 00000000..d1b1f194 --- /dev/null +++ b/src/server/routes/column-privileges.ts @@ -0,0 +1,134 @@ +import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' +import { Type } from '@sinclair/typebox' +import { PostgresMeta } from '../../lib/index.js' +import { + postgresColumnPrivilegesGrantSchema, + postgresColumnPrivilegesRevokeSchema, + postgresColumnPrivilegesSchema, +} from '../../lib/types.js' +import { createConnectionConfig } from '../utils.js' +import { extractRequestForLogging, translateErrorToResponseCode } from '../utils.js' + +const route: FastifyPluginAsyncTypebox = async (fastify) => { + fastify.get( + '/', + { + schema: { + headers: Type.Object({ + pg: Type.String(), + 'x-pg-application-name': Type.Optional(Type.String()), + }), + querystring: Type.Object({ + include_system_schemas: Type.Optional(Type.Boolean()), + // Note: this only supports comma separated values (e.g., "...?included_schemas=public,core") + included_schemas: Type.Optional(Type.String()), + excluded_schemas: Type.Optional(Type.String()), + limit: Type.Optional(Type.Integer()), + offset: Type.Optional(Type.Integer()), + }), + response: { + 200: Type.Array(postgresColumnPrivilegesSchema), + 500: Type.Object({ + error: Type.String(), + }), + }, + }, + }, + async (request, reply) => { + const config = createConnectionConfig(request) + const includeSystemSchemas = request.query.include_system_schemas + const includedSchemas = request.query.included_schemas?.split(',') + const excludedSchemas = request.query.excluded_schemas?.split(',') + const limit = request.query.limit + const offset = request.query.offset + + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.columnPrivileges.list({ + includeSystemSchemas, + includedSchemas, + excludedSchemas, + limit, + offset, + }) + await pgMeta.end() + if (error) { + request.log.error({ error, request: extractRequestForLogging(request) }) + reply.code(translateErrorToResponseCode(error, 500)) + return { error: error.message } + } + + return data + } + ) + + fastify.post( + '/', + { + schema: { + headers: Type.Object({ + pg: Type.String(), + 'x-pg-application-name': Type.Optional(Type.String()), + }), + body: Type.Array(postgresColumnPrivilegesGrantSchema), + response: { + 200: Type.Array(postgresColumnPrivilegesSchema), + 400: Type.Object({ + error: Type.String(), + }), + }, + }, + }, + async (request, reply) => { + const config = createConnectionConfig(request) + + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.columnPrivileges.grant(request.body) + await pgMeta.end() + if (error) { + request.log.error({ error, request: extractRequestForLogging(request) }) + reply.code(400) + return { error: error.message } + } + + return data + } + ) + + fastify.delete( + '/', + { + schema: { + headers: Type.Object({ + pg: Type.String(), + 'x-pg-application-name': Type.Optional(Type.String()), + }), + body: Type.Array(postgresColumnPrivilegesRevokeSchema), + response: { + 200: Type.Array(postgresColumnPrivilegesSchema), + 400: Type.Object({ + error: Type.String(), + }), + 404: Type.Object({ + error: Type.String(), + }), + }, + }, + }, + async (request, reply) => { + const config = createConnectionConfig(request) + + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.columnPrivileges.revoke(request.body) + await pgMeta.end() + if (error) { + request.log.error({ error, request: extractRequestForLogging(request) }) + reply.code(400) + if (error.message.startsWith('Cannot find')) reply.code(404) + return { error: error.message } + } + + return data + } + ) +} +export default route diff --git a/src/server/routes/columns.ts b/src/server/routes/columns.ts index 9451702b..21e12364 100644 --- a/src/server/routes/columns.ts +++ b/src/server/routes/columns.ts @@ -1,121 +1,247 @@ -import { FastifyInstance } from 'fastify' -import { PostgresMeta } from '../../lib' -import { DEFAULT_POOL_CONFIG } from '../constants' -import { extractRequestForLogging } from '../utils' - -export default async (fastify: FastifyInstance) => { - fastify.get<{ - Headers: { pg: string } - Querystring: { - include_system_schemas?: string - limit?: number - offset?: number - } - }>('/', async (request, reply) => { - const connectionString = request.headers.pg - const includeSystemSchemas = request.query.include_system_schemas === 'true' - const limit = request.query.limit - const offset = request.query.offset - - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) - const { data, error } = await pgMeta.columns.list({ - includeSystemSchemas, - limit, - offset, - }) - await pgMeta.end() - if (error) { - request.log.error({ error, request: extractRequestForLogging(request) }) - reply.code(500) - return { error: error.message } - } +import { PostgresMeta } from '../../lib/index.js' +import { createConnectionConfig, extractRequestForLogging } from '../utils.js' +import { Type } from '@sinclair/typebox' +import { + postgresColumnCreateSchema, + postgresColumnSchema, + postgresColumnUpdateSchema, +} from '../../lib/types.js' +import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' - return data - }) +const route: FastifyPluginAsyncTypebox = async (fastify) => { + fastify.get( + '/', + { + schema: { + headers: Type.Object({ + pg: Type.String(), + 'x-pg-application-name': Type.Optional(Type.String()), + }), + querystring: Type.Object({ + include_system_schemas: Type.Optional(Type.Boolean()), + included_schemas: Type.Optional(Type.String()), + excluded_schemas: Type.Optional(Type.String()), + limit: Type.Optional(Type.Integer()), + offset: Type.Optional(Type.Integer()), + }), + response: { + 200: Type.Array(postgresColumnSchema), + 500: Type.Object({ + error: Type.String(), + }), + }, + }, + }, + async (request, reply) => { + const includeSystemSchemas = request.query.include_system_schemas + const includedSchemas = request.query.included_schemas?.split(',') + const excludedSchemas = request.query.excluded_schemas?.split(',') + const limit = request.query.limit + const offset = request.query.offset - fastify.get<{ - Headers: { pg: string } - Params: { - id: string - } - }>('/:id(\\d+\\.\\d+)', async (request, reply) => { - const connectionString = request.headers.pg - - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) - const { data, error } = await pgMeta.columns.retrieve({ id: request.params.id }) - await pgMeta.end() - if (error) { - request.log.error({ error, request: extractRequestForLogging(request) }) - reply.code(400) - if (error.message.startsWith('Cannot find')) reply.code(404) - return { error: error.message } - } + const config = createConnectionConfig(request) + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.columns.list({ + includeSystemSchemas, + includedSchemas, + excludedSchemas, + limit, + offset, + }) + await pgMeta.end() + if (error) { + request.log.error({ error, request: extractRequestForLogging(request) }) + reply.code(500) + return { error: error.message } + } - return data - }) - - fastify.post<{ - Headers: { pg: string } - Body: any - }>('/', async (request, reply) => { - const connectionString = request.headers.pg - - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) - const { data, error } = await pgMeta.columns.create(request.body) - await pgMeta.end() - if (error) { - request.log.error({ error, request: extractRequestForLogging(request) }) - reply.code(400) - if (error.message.startsWith('Cannot find')) reply.code(404) - return { error: error.message } + return data } + ) - return data - }) + fastify.get( + '/:tableId(^\\d+):ordinalPosition', + { + schema: { + headers: Type.Object({ + pg: Type.String(), + 'x-pg-application-name': Type.Optional(Type.String()), + }), + params: Type.Object({ + tableId: Type.String(), + ordinalPosition: Type.String(), + }), + querystring: Type.Object({ + include_system_schemas: Type.Optional(Type.Boolean()), + limit: Type.Optional(Type.Integer()), + offset: Type.Optional(Type.Integer()), + }), + response: { + 200: postgresColumnSchema, + 400: Type.Object({ + error: Type.String(), + }), + }, + }, + }, + async (request, reply) => { + if (request.params.ordinalPosition === '') { + const { + query: { limit, offset }, + params: { tableId }, + } = request + const includeSystemSchemas = request.query.include_system_schemas - fastify.patch<{ - Headers: { pg: string } - Params: { - id: string - } - Body: any - }>('/:id(\\d+\\.\\d+)', async (request, reply) => { - const connectionString = request.headers.pg - - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) - const { data, error } = await pgMeta.columns.update(request.params.id, request.body) - await pgMeta.end() - if (error) { - request.log.error({ error, request: extractRequestForLogging(request) }) - reply.code(400) - if (error.message.startsWith('Cannot find')) reply.code(404) - return { error: error.message } - } + const config = createConnectionConfig(request) + const pgMeta: PostgresMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.columns.list({ + tableId: Number(tableId), + includeSystemSchemas, + limit: Number(limit), + offset: Number(offset), + }) + await pgMeta.end() + if (error) { + request.log.error({ error, request: extractRequestForLogging(request) }) + reply.code(500) + return { error: error.message } + } - return data - }) + return data[0] + } else if (/^\.\d+$/.test(request.params.ordinalPosition)) { + const { + params: { tableId, ordinalPosition: ordinalPositionWithDot }, + } = request + const ordinalPosition = ordinalPositionWithDot.slice(1) - fastify.delete<{ - Headers: { pg: string } - Params: { - id: string + const config = createConnectionConfig(request) + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.columns.retrieve({ + id: `${tableId}.${ordinalPosition}`, + }) + await pgMeta.end() + if (error) { + request.log.error({ error, request: extractRequestForLogging(request) }) + reply.code(400) + if (error.message.startsWith('Cannot find')) reply.code(404) + return { error: error.message } + } + + return data + } else { + return reply.callNotFound() + } } - Querystring: { - cascade?: string + ) + + fastify.post( + '/', + { + schema: { + headers: Type.Object({ + pg: Type.String(), + 'x-pg-application-name': Type.Optional(Type.String()), + }), + body: postgresColumnCreateSchema, + response: { + 200: postgresColumnSchema, + 400: Type.Object({ + error: Type.String(), + }), + }, + }, + }, + async (request, reply) => { + const config = createConnectionConfig(request) + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.columns.create(request.body) + await pgMeta.end() + if (error) { + request.log.error({ error, request: extractRequestForLogging(request) }) + reply.code(400) + if (error.message.startsWith('Cannot find')) reply.code(404) + return { error: error.message } + } + + return data } - }>('/:id(\\d+\\.\\d+)', async (request, reply) => { - const connectionString = request.headers.pg - - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) - const { data, error } = await pgMeta.columns.remove(request.params.id) - await pgMeta.end() - if (error) { - request.log.error({ error, request: extractRequestForLogging(request) }) - reply.code(400) - if (error.message.startsWith('Cannot find')) reply.code(404) - return { error: error.message } + ) + + fastify.patch( + '/:id(\\d+\\.\\d+)', + { + schema: { + headers: Type.Object({ + pg: Type.String(), + 'x-pg-application-name': Type.Optional(Type.String()), + }), + params: Type.Object({ + id: Type.String(), + }), + body: postgresColumnUpdateSchema, + response: { + 200: postgresColumnSchema, + 400: Type.Object({ + error: Type.String(), + }), + }, + }, + }, + async (request, reply) => { + const config = createConnectionConfig(request) + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.columns.update(request.params.id, request.body) + await pgMeta.end() + if (error) { + request.log.error({ error, request: extractRequestForLogging(request) }) + reply.code(400) + if (error.message.startsWith('Cannot find')) reply.code(404) + return { error: error.message } + } + + return data } + ) + + fastify.delete( + '/:id(\\d+\\.\\d+)', + { + schema: { + headers: Type.Object({ + pg: Type.String(), + 'x-pg-application-name': Type.Optional(Type.String()), + }), + params: Type.Object({ + id: Type.String(), + }), + querystring: Type.Object({ + cascade: Type.Optional(Type.String()), + }), + response: { + 200: postgresColumnSchema, + 400: Type.Object({ + error: Type.String(), + }), + }, + }, + }, + async (request, reply) => { + const cascade = request.query.cascade === 'true' - return data - }) + const config = createConnectionConfig(request) + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.columns.remove(request.params.id, { cascade }) + await pgMeta.end() + if (error) { + request.log.error({ error, request: extractRequestForLogging(request) }) + reply.code(400) + if (error.message.startsWith('Cannot find')) reply.code(404) + return { error: error.message } + } + + return data + } + ) } + +export default route diff --git a/src/server/routes/config.ts b/src/server/routes/config.ts index a314b30b..a2faf9db 100644 --- a/src/server/routes/config.ts +++ b/src/server/routes/config.ts @@ -1,21 +1,21 @@ import { FastifyInstance } from 'fastify' -import { PostgresMeta } from '../../lib' -import { DEFAULT_POOL_CONFIG } from '../constants' -import { extractRequestForLogging } from '../utils' +import { PostgresMeta } from '../../lib/index.js' +import { createConnectionConfig } from '../utils.js' +import { extractRequestForLogging } from '../utils.js' export default async (fastify: FastifyInstance) => { fastify.get<{ - Headers: { pg: string } + Headers: { pg: string; 'x-pg-application-name'?: string } Querystring: { limit?: number offset?: number } }>('/', async (request, reply) => { - const connectionString = request.headers.pg + const config = createConnectionConfig(request) const limit = request.query.limit const offset = request.query.offset - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) + const pgMeta = new PostgresMeta(config) const { data, error } = await pgMeta.config.list({ limit, offset }) await pgMeta.end() if (error) { @@ -28,11 +28,11 @@ export default async (fastify: FastifyInstance) => { }) fastify.get<{ - Headers: { pg: string } + Headers: { pg: string; 'x-pg-application-name'?: string } }>('/version', async (request, reply) => { - const connectionString = request.headers.pg + const config = createConnectionConfig(request) - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) + const pgMeta = new PostgresMeta(config) const { data, error } = await pgMeta.version.retrieve() await pgMeta.end() if (error) { diff --git a/src/server/routes/extensions.ts b/src/server/routes/extensions.ts index 54e803bc..b202c251 100644 --- a/src/server/routes/extensions.ts +++ b/src/server/routes/extensions.ts @@ -1,21 +1,21 @@ import { FastifyInstance } from 'fastify' -import { PostgresMeta } from '../../lib' -import { DEFAULT_POOL_CONFIG } from '../constants' -import { extractRequestForLogging } from '../utils' +import { PostgresMeta } from '../../lib/index.js' +import { createConnectionConfig } from '../utils.js' +import { extractRequestForLogging } from '../utils.js' export default async (fastify: FastifyInstance) => { fastify.get<{ - Headers: { pg: string } + Headers: { pg: string; 'x-pg-application-name'?: string } Querystring: { limit?: number offset?: number } }>('/', async (request, reply) => { - const connectionString = request.headers.pg + const config = createConnectionConfig(request) const limit = request.query.limit const offset = request.query.offset - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) + const pgMeta = new PostgresMeta(config) const { data, error } = await pgMeta.extensions.list({ limit, offset }) await pgMeta.end() if (error) { @@ -28,14 +28,14 @@ export default async (fastify: FastifyInstance) => { }) fastify.get<{ - Headers: { pg: string } + Headers: { pg: string; 'x-pg-application-name'?: string } Params: { name: string } }>('/:name', async (request, reply) => { - const connectionString = request.headers.pg + const config = createConnectionConfig(request) - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) + const pgMeta = new PostgresMeta(config) const { data, error } = await pgMeta.extensions.retrieve({ name: request.params.name }) await pgMeta.end() if (error) { @@ -48,13 +48,13 @@ export default async (fastify: FastifyInstance) => { }) fastify.post<{ - Headers: { pg: string } + Headers: { pg: string; 'x-pg-application-name'?: string } Body: any }>('/', async (request, reply) => { - const connectionString = request.headers.pg + const config = createConnectionConfig(request) - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) - const { data, error } = await pgMeta.extensions.create(request.body) + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.extensions.create(request.body as any) await pgMeta.end() if (error) { request.log.error({ error, request: extractRequestForLogging(request) }) @@ -66,16 +66,16 @@ export default async (fastify: FastifyInstance) => { }) fastify.patch<{ - Headers: { pg: string } + Headers: { pg: string; 'x-pg-application-name'?: string } Params: { name: string } Body: any }>('/:name', async (request, reply) => { - const connectionString = request.headers.pg + const config = createConnectionConfig(request) - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) - const { data, error } = await pgMeta.extensions.update(request.params.name, request.body) + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.extensions.update(request.params.name, request.body as any) await pgMeta.end() if (error) { request.log.error({ error, request: extractRequestForLogging(request) }) @@ -88,7 +88,7 @@ export default async (fastify: FastifyInstance) => { }) fastify.delete<{ - Headers: { pg: string } + Headers: { pg: string; 'x-pg-application-name'?: string } Params: { name: string } @@ -96,10 +96,10 @@ export default async (fastify: FastifyInstance) => { cascade?: string } }>('/:name', async (request, reply) => { - const connectionString = request.headers.pg + const config = createConnectionConfig(request) const cascade = request.query.cascade === 'true' - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) + const pgMeta = new PostgresMeta(config) const { data, error } = await pgMeta.extensions.remove(request.params.name, { cascade }) await pgMeta.end() if (error) { diff --git a/src/server/routes/foreign-tables.ts b/src/server/routes/foreign-tables.ts new file mode 100644 index 00000000..4de924f6 --- /dev/null +++ b/src/server/routes/foreign-tables.ts @@ -0,0 +1,85 @@ +import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' +import { Type } from '@sinclair/typebox' +import { PostgresMeta } from '../../lib/index.js' +import { postgresForeignTableSchema } from '../../lib/types.js' +import { createConnectionConfig } from '../utils.js' +import { extractRequestForLogging } from '../utils.js' + +const route: FastifyPluginAsyncTypebox = async (fastify) => { + fastify.get( + '/', + { + schema: { + headers: Type.Object({ + pg: Type.String(), + 'x-pg-application-name': Type.Optional(Type.String()), + }), + querystring: Type.Object({ + limit: Type.Optional(Type.Integer()), + offset: Type.Optional(Type.Integer()), + include_columns: Type.Optional(Type.Boolean()), + }), + response: { + 200: Type.Array(postgresForeignTableSchema), + 500: Type.Object({ + error: Type.String(), + }), + }, + }, + }, + async (request, reply) => { + const config = createConnectionConfig(request) + const limit = request.query.limit + const offset = request.query.offset + const includeColumns = request.query.include_columns + + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.foreignTables.list({ limit, offset, includeColumns }) + await pgMeta.end() + if (error) { + request.log.error({ error, request: extractRequestForLogging(request) }) + reply.code(500) + return { error: error.message } + } + + return data + } + ) + + fastify.get( + '/:id(\\d+)', + { + schema: { + headers: Type.Object({ + pg: Type.String(), + 'x-pg-application-name': Type.Optional(Type.String()), + }), + params: Type.Object({ + id: Type.Integer(), + }), + response: { + 200: postgresForeignTableSchema, + 404: Type.Object({ + error: Type.String(), + }), + }, + }, + }, + async (request, reply) => { + const config = createConnectionConfig(request) + const id = request.params.id + + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.foreignTables.retrieve({ id }) + await pgMeta.end() + if (error) { + request.log.error({ error, request: extractRequestForLogging(request) }) + reply.code(404) + return { error: error.message } + } + + return data + } + ) +} +export default route diff --git a/src/server/routes/functions.ts b/src/server/routes/functions.ts index 2e598c6a..51fd5737 100644 --- a/src/server/routes/functions.ts +++ b/src/server/routes/functions.ts @@ -1,24 +1,35 @@ import { FastifyInstance } from 'fastify' -import { PostgresMeta } from '../../lib' -import { DEFAULT_POOL_CONFIG } from '../constants' -import { extractRequestForLogging } from '../utils' +import { PostgresMeta } from '../../lib/index.js' +import { createConnectionConfig } from '../utils.js' +import { extractRequestForLogging } from '../utils.js' export default async (fastify: FastifyInstance) => { fastify.get<{ - Headers: { pg: string } + Headers: { pg: string; 'x-pg-application-name'?: string } Querystring: { include_system_schemas?: string + // Note: this only supports comma separated values (e.g., ".../functions?included_schemas=public,core") + included_schemas?: string + excluded_schemas?: string limit?: number offset?: number } }>('/', async (request, reply) => { - const connectionString = request.headers.pg + const config = createConnectionConfig(request) const includeSystemSchemas = request.query.include_system_schemas === 'true' + const includedSchemas = request.query.included_schemas?.split(',') + const excludedSchemas = request.query.excluded_schemas?.split(',') const limit = request.query.limit const offset = request.query.offset - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) - const { data, error } = await pgMeta.functions.list({ includeSystemSchemas, limit, offset }) + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.functions.list({ + includeSystemSchemas, + includedSchemas, + excludedSchemas, + limit, + offset, + }) await pgMeta.end() if (error) { request.log.error({ error, request: extractRequestForLogging(request) }) @@ -30,15 +41,15 @@ export default async (fastify: FastifyInstance) => { }) fastify.get<{ - Headers: { pg: string } + Headers: { pg: string; 'x-pg-application-name'?: string } Params: { id: string } }>('/:id(\\d+)', async (request, reply) => { - const connectionString = request.headers.pg + const config = createConnectionConfig(request) const id = Number(request.params.id) - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) + const pgMeta = new PostgresMeta(config) const { data, error } = await pgMeta.functions.retrieve({ id }) await pgMeta.end() if (error) { @@ -51,13 +62,13 @@ export default async (fastify: FastifyInstance) => { }) fastify.post<{ - Headers: { pg: string } + Headers: { pg: string; 'x-pg-application-name'?: string } Body: any }>('/', async (request, reply) => { - const connectionString = request.headers.pg + const config = createConnectionConfig(request) - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) - const { data, error } = await pgMeta.functions.create(request.body) + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.functions.create(request.body as any) await pgMeta.end() if (error) { request.log.error({ error, request: extractRequestForLogging(request) }) @@ -68,17 +79,17 @@ export default async (fastify: FastifyInstance) => { }) fastify.patch<{ - Headers: { pg: string } + Headers: { pg: string; 'x-pg-application-name'?: string } Params: { id: string } Body: any }>('/:id(\\d+)', async (request, reply) => { - const connectionString = request.headers.pg + const config = createConnectionConfig(request) const id = Number(request.params.id) - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) - const { data, error } = await pgMeta.functions.update(id, request.body) + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.functions.update(id, request.body as any) await pgMeta.end() if (error) { request.log.error({ error, request: extractRequestForLogging(request) }) @@ -90,15 +101,15 @@ export default async (fastify: FastifyInstance) => { }) fastify.delete<{ - Headers: { pg: string } + Headers: { pg: string; 'x-pg-application-name'?: string } Params: { id: string } }>('/:id(\\d+)', async (request, reply) => { - const connectionString = request.headers.pg + const config = createConnectionConfig(request) const id = Number(request.params.id) - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) + const pgMeta = new PostgresMeta(config) const { data, error } = await pgMeta.functions.remove(id) await pgMeta.end() if (error) { diff --git a/src/server/routes/generators/go.ts b/src/server/routes/generators/go.ts new file mode 100644 index 00000000..fa85fa46 --- /dev/null +++ b/src/server/routes/generators/go.ts @@ -0,0 +1,34 @@ +import type { FastifyInstance } from 'fastify' +import { PostgresMeta } from '../../../lib/index.js' +import { createConnectionConfig, extractRequestForLogging } from '../../utils.js' +import { apply as applyGoTemplate } from '../../templates/go.js' +import { getGeneratorMetadata } from '../../../lib/generators.js' + +export default async (fastify: FastifyInstance) => { + fastify.get<{ + Headers: { pg: string; 'x-pg-application-name'?: string } + Querystring: { + excluded_schemas?: string + included_schemas?: string + } + }>('/', async (request, reply) => { + const config = createConnectionConfig(request) + const excludedSchemas = + request.query.excluded_schemas?.split(',').map((schema) => schema.trim()) ?? [] + const includedSchemas = + request.query.included_schemas?.split(',').map((schema) => schema.trim()) ?? [] + + const pgMeta: PostgresMeta = new PostgresMeta(config) + const { data: generatorMeta, error: generatorMetaError } = await getGeneratorMetadata(pgMeta, { + includedSchemas, + excludedSchemas, + }) + if (generatorMetaError) { + request.log.error({ error: generatorMetaError, request: extractRequestForLogging(request) }) + reply.code(500) + return { error: generatorMetaError.message } + } + + return applyGoTemplate(generatorMeta) + }) +} diff --git a/src/server/routes/generators/swift.ts b/src/server/routes/generators/swift.ts new file mode 100644 index 00000000..e02839fb --- /dev/null +++ b/src/server/routes/generators/swift.ts @@ -0,0 +1,39 @@ +import type { FastifyInstance } from 'fastify' +import { PostgresMeta } from '../../../lib/index.js' +import { createConnectionConfig, extractRequestForLogging } from '../../utils.js' +import { apply as applySwiftTemplate, AccessControl } from '../../templates/swift.js' +import { getGeneratorMetadata } from '../../../lib/generators.js' + +export default async (fastify: FastifyInstance) => { + fastify.get<{ + Headers: { pg: string; 'x-pg-application-name'?: string } + Querystring: { + excluded_schemas?: string + included_schemas?: string + access_control?: AccessControl + } + }>('/', async (request, reply) => { + const config = createConnectionConfig(request) + const excludedSchemas = + request.query.excluded_schemas?.split(',').map((schema) => schema.trim()) ?? [] + const includedSchemas = + request.query.included_schemas?.split(',').map((schema) => schema.trim()) ?? [] + const accessControl = request.query.access_control ?? 'internal' + + const pgMeta: PostgresMeta = new PostgresMeta(config) + const { data: generatorMeta, error: generatorMetaError } = await getGeneratorMetadata(pgMeta, { + includedSchemas, + excludedSchemas, + }) + if (generatorMetaError) { + request.log.error({ error: generatorMetaError, request: extractRequestForLogging(request) }) + reply.code(500) + return { error: generatorMetaError.message } + } + + return applySwiftTemplate({ + ...generatorMeta, + accessControl, + }) + }) +} diff --git a/src/server/routes/generators/typescript.ts b/src/server/routes/generators/typescript.ts new file mode 100644 index 00000000..3e615b32 --- /dev/null +++ b/src/server/routes/generators/typescript.ts @@ -0,0 +1,39 @@ +import type { FastifyInstance } from 'fastify' +import { PostgresMeta } from '../../../lib/index.js' +import { createConnectionConfig, extractRequestForLogging } from '../../utils.js' +import { apply as applyTypescriptTemplate } from '../../templates/typescript.js' +import { getGeneratorMetadata } from '../../../lib/generators.js' + +export default async (fastify: FastifyInstance) => { + fastify.get<{ + Headers: { pg: string; 'x-pg-application-name'?: string } + Querystring: { + excluded_schemas?: string + included_schemas?: string + detect_one_to_one_relationships?: string + } + }>('/', async (request, reply) => { + const config = createConnectionConfig(request) + const excludedSchemas = + request.query.excluded_schemas?.split(',').map((schema) => schema.trim()) ?? [] + const includedSchemas = + request.query.included_schemas?.split(',').map((schema) => schema.trim()) ?? [] + const detectOneToOneRelationships = request.query.detect_one_to_one_relationships === 'true' + + const pgMeta: PostgresMeta = new PostgresMeta(config) + const { data: generatorMeta, error: generatorMetaError } = await getGeneratorMetadata(pgMeta, { + includedSchemas, + excludedSchemas, + }) + if (generatorMetaError) { + request.log.error({ error: generatorMetaError, request: extractRequestForLogging(request) }) + reply.code(500) + return { error: generatorMetaError.message } + } + + return applyTypescriptTemplate({ + ...generatorMeta, + detectOneToOneRelationships, + }) + }) +} diff --git a/src/server/routes/index.ts b/src/server/routes/index.ts index 70feea86..1532c4ea 100644 --- a/src/server/routes/index.ts +++ b/src/server/routes/index.ts @@ -1,41 +1,85 @@ -import * as CryptoJS from 'crypto-js' +import CryptoJS from 'crypto-js' import { FastifyInstance } from 'fastify' -import { PG_CONNECTION, CRYPTO_KEY } from '../constants' +import ColumnPrivilegesRoute from './column-privileges.js' +import ColumnRoute from './columns.js' +import ConfigRoute from './config.js' +import ExtensionsRoute from './extensions.js' +import ForeignTablesRoute from './foreign-tables.js' +import FunctionsRoute from './functions.js' +import IndexesRoute from './indexes.js' +import MaterializedViewsRoute from './materialized-views.js' +import PoliciesRoute from './policies.js' +import PublicationsRoute from './publications.js' +import QueryRoute from './query.js' +import SchemasRoute from './schemas.js' +import RolesRoute from './roles.js' +import TablePrivilegesRoute from './table-privileges.js' +import TablesRoute from './tables.js' +import TriggersRoute from './triggers.js' +import TypesRoute from './types.js' +import ViewsRoute from './views.js' +import TypeScriptTypeGenRoute from './generators/typescript.js' +import GoTypeGenRoute from './generators/go.js' +import SwiftTypeGenRoute from './generators/swift.js' +import { PG_CONNECTION, CRYPTO_KEY } from '../constants.js' export default async (fastify: FastifyInstance) => { // Adds a "pg" object to the request if it doesn't exist fastify.addHook('onRequest', (request, _reply, done) => { - // Node converts headers to lowercase - const encryptedHeader = request.headers['x-connection-encrypted']?.toString() - if (encryptedHeader) { + try { + // Node converts headers to lowercase + const encryptedHeader = request.headers['x-connection-encrypted']?.toString() + if (encryptedHeader) { + try { + request.headers.pg = CryptoJS.AES.decrypt(encryptedHeader, CRYPTO_KEY) + .toString(CryptoJS.enc.Utf8) + .trim() + } catch (e: any) { + request.log.warn({ + message: 'failed to parse encrypted connstring', + error: e.toString(), + }) + throw new Error('failed to process upstream connection details') + } + } else { + request.headers.pg = PG_CONNECTION + } + if (!request.headers.pg) { + request.log.error({ message: 'failed to get connection string' }) + throw new Error('failed to get upstream connection details') + } + // Ensure the resulting connection string is a valid URL try { - request.headers.pg = CryptoJS.AES.decrypt(encryptedHeader, CRYPTO_KEY).toString( - CryptoJS.enc.Utf8 - ) - } catch (e: any) { - request.log.warn({ - message: 'failed to parse encrypted connstring', - error: e.toString(), - }) + new URL(request.headers.pg) + } catch (error) { + request.log.error({ message: 'pg connection string is invalid url' }) throw new Error('failed to process upstream connection details') } - } else { - request.headers.pg = PG_CONNECTION + return done() + } catch (err) { + return done(err as Error) } - done() }) - fastify.register(require('./columns'), { prefix: '/columns' }) - fastify.register(require('./config'), { prefix: '/config' }) - fastify.register(require('./extensions'), { prefix: '/extensions' }) - fastify.register(require('./functions'), { prefix: '/functions' }) - fastify.register(require('./policies'), { prefix: '/policies' }) - fastify.register(require('./publications'), { prefix: '/publications' }) - fastify.register(require('./query'), { prefix: '/query' }) - fastify.register(require('./schemas'), { prefix: '/schemas' }) - fastify.register(require('./roles'), { prefix: '/roles' }) - fastify.register(require('./tables'), { prefix: '/tables' }) - fastify.register(require('./triggers'), { prefix: '/triggers' }) - fastify.register(require('./types'), { prefix: '/types' }) - fastify.register(require('./views'), { prefix: '/views' }) + fastify.register(ColumnPrivilegesRoute, { prefix: '/column-privileges' }) + fastify.register(ColumnRoute, { prefix: '/columns' }) + fastify.register(ConfigRoute, { prefix: '/config' }) + fastify.register(ExtensionsRoute, { prefix: '/extensions' }) + fastify.register(ForeignTablesRoute, { prefix: '/foreign-tables' }) + fastify.register(FunctionsRoute, { prefix: '/functions' }) + fastify.register(IndexesRoute, { prefix: '/indexes' }) + fastify.register(MaterializedViewsRoute, { prefix: '/materialized-views' }) + fastify.register(PoliciesRoute, { prefix: '/policies' }) + fastify.register(PublicationsRoute, { prefix: '/publications' }) + fastify.register(QueryRoute, { prefix: '/query' }) + fastify.register(SchemasRoute, { prefix: '/schemas' }) + fastify.register(RolesRoute, { prefix: '/roles' }) + fastify.register(TablePrivilegesRoute, { prefix: '/table-privileges' }) + fastify.register(TablesRoute, { prefix: '/tables' }) + fastify.register(TriggersRoute, { prefix: '/triggers' }) + fastify.register(TypesRoute, { prefix: '/types' }) + fastify.register(ViewsRoute, { prefix: '/views' }) + fastify.register(TypeScriptTypeGenRoute, { prefix: '/generators/typescript' }) + fastify.register(GoTypeGenRoute, { prefix: '/generators/go' }) + fastify.register(SwiftTypeGenRoute, { prefix: '/generators/swift' }) } diff --git a/src/server/routes/indexes.ts b/src/server/routes/indexes.ts new file mode 100644 index 00000000..b024ea09 --- /dev/null +++ b/src/server/routes/indexes.ts @@ -0,0 +1,62 @@ +import { FastifyInstance } from 'fastify' +import { PostgresMeta } from '../../lib/index.js' +import { createConnectionConfig, extractRequestForLogging } from '../utils.js' + +export default async (fastify: FastifyInstance) => { + fastify.get<{ + Headers: { pg: string; 'x-pg-application-name'?: string } + Querystring: { + include_system_schemas?: string + // Note: this only supports comma separated values (e.g., ".../functions?included_schemas=public,core") + included_schemas?: string + excluded_schemas?: string + limit?: number + offset?: number + } + }>('/', async (request, reply) => { + const config = createConnectionConfig(request) + const includeSystemSchemas = request.query.include_system_schemas === 'true' + const includedSchemas = request.query.included_schemas?.split(',') + const excludedSchemas = request.query.excluded_schemas?.split(',') + const limit = request.query.limit + const offset = request.query.offset + + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.indexes.list({ + includeSystemSchemas, + includedSchemas, + excludedSchemas, + limit, + offset, + }) + await pgMeta.end() + if (error) { + request.log.error({ error, request: extractRequestForLogging(request) }) + reply.code(500) + return { error: error.message } + } + + return data + }) + + fastify.get<{ + Headers: { pg: string; 'x-pg-application-name'?: string } + Params: { + id: string + } + }>('/:id(\\d+)', async (request, reply) => { + const config = createConnectionConfig(request) + const id = Number(request.params.id) + + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.indexes.retrieve({ id }) + await pgMeta.end() + if (error) { + request.log.error({ error, request: extractRequestForLogging(request) }) + reply.code(404) + return { error: error.message } + } + + return data + }) +} diff --git a/src/server/routes/materialized-views.ts b/src/server/routes/materialized-views.ts new file mode 100644 index 00000000..9a5a0b4f --- /dev/null +++ b/src/server/routes/materialized-views.ts @@ -0,0 +1,95 @@ +import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' +import { Type } from '@sinclair/typebox' +import { PostgresMeta } from '../../lib/index.js' +import { postgresMaterializedViewSchema } from '../../lib/types.js' +import { createConnectionConfig } from '../utils.js' +import { extractRequestForLogging } from '../utils.js' + +const route: FastifyPluginAsyncTypebox = async (fastify) => { + fastify.get( + '/', + { + schema: { + headers: Type.Object({ + pg: Type.String(), + 'x-pg-application-name': Type.Optional(Type.String()), + }), + querystring: Type.Object({ + included_schemas: Type.Optional(Type.String()), + excluded_schemas: Type.Optional(Type.String()), + limit: Type.Optional(Type.Integer()), + offset: Type.Optional(Type.Integer()), + include_columns: Type.Optional(Type.Boolean()), + }), + response: { + 200: Type.Array(postgresMaterializedViewSchema), + 500: Type.Object({ + error: Type.String(), + }), + }, + }, + }, + async (request, reply) => { + const config = createConnectionConfig(request) + const includedSchemas = request.query.included_schemas?.split(',') + const excludedSchemas = request.query.excluded_schemas?.split(',') + const limit = request.query.limit + const offset = request.query.offset + const includeColumns = request.query.include_columns + + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.materializedViews.list({ + includedSchemas, + excludedSchemas, + limit, + offset, + includeColumns, + }) + await pgMeta.end() + if (error) { + request.log.error({ error, request: extractRequestForLogging(request) }) + reply.code(500) + return { error: error.message } + } + + return data + } + ) + + fastify.get( + '/:id(\\d+)', + { + schema: { + headers: Type.Object({ + pg: Type.String(), + 'x-pg-application-name': Type.Optional(Type.String()), + }), + params: Type.Object({ + id: Type.Integer(), + }), + response: { + 200: postgresMaterializedViewSchema, + 404: Type.Object({ + error: Type.String(), + }), + }, + }, + }, + async (request, reply) => { + const config = createConnectionConfig(request) + const id = request.params.id + + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.materializedViews.retrieve({ id }) + await pgMeta.end() + if (error) { + request.log.error({ error, request: extractRequestForLogging(request) }) + reply.code(404) + return { error: error.message } + } + + return data + } + ) +} +export default route diff --git a/src/server/routes/policies.ts b/src/server/routes/policies.ts index 7b479fa6..4e951ad3 100644 --- a/src/server/routes/policies.ts +++ b/src/server/routes/policies.ts @@ -1,24 +1,35 @@ import { FastifyInstance } from 'fastify' -import { PostgresMeta } from '../../lib' -import { DEFAULT_POOL_CONFIG } from '../constants' -import { extractRequestForLogging } from '../utils' +import { PostgresMeta } from '../../lib/index.js' +import { createConnectionConfig } from '../utils.js' +import { extractRequestForLogging } from '../utils.js' export default async (fastify: FastifyInstance) => { fastify.get<{ - Headers: { pg: string } + Headers: { pg: string; 'x-pg-application-name'?: string } Querystring: { include_system_schemas?: string + // Note: this only supports comma separated values (e.g., ".../policies?included_schemas=public,core") + included_schemas?: string + excluded_schemas?: string limit?: number offset?: number } }>('/', async (request, reply) => { - const connectionString = request.headers.pg + const config = createConnectionConfig(request) const includeSystemSchemas = request.query.include_system_schemas === 'true' + const includedSchemas = request.query.included_schemas?.split(',') + const excludedSchemas = request.query.excluded_schemas?.split(',') const limit = request.query.limit const offset = request.query.offset - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) - const { data, error } = await pgMeta.policies.list({ includeSystemSchemas, limit, offset }) + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.policies.list({ + includeSystemSchemas, + includedSchemas, + excludedSchemas, + limit, + offset, + }) await pgMeta.end() if (error) { request.log.error({ error, request: extractRequestForLogging(request) }) @@ -30,15 +41,15 @@ export default async (fastify: FastifyInstance) => { }) fastify.get<{ - Headers: { pg: string } + Headers: { pg: string; 'x-pg-application-name'?: string } Params: { id: string } }>('/:id(\\d+)', async (request, reply) => { - const connectionString = request.headers.pg + const config = createConnectionConfig(request) const id = Number(request.params.id) - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) + const pgMeta = new PostgresMeta(config) const { data, error } = await pgMeta.policies.retrieve({ id }) await pgMeta.end() if (error) { @@ -51,13 +62,13 @@ export default async (fastify: FastifyInstance) => { }) fastify.post<{ - Headers: { pg: string } + Headers: { pg: string; 'x-pg-application-name'?: string } Body: any }>('/', async (request, reply) => { - const connectionString = request.headers.pg + const config = createConnectionConfig(request) - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) - const { data, error } = await pgMeta.policies.create(request.body) + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.policies.create(request.body as any) await pgMeta.end() if (error) { request.log.error({ error, request: extractRequestForLogging(request) }) @@ -69,17 +80,17 @@ export default async (fastify: FastifyInstance) => { }) fastify.patch<{ - Headers: { pg: string } + Headers: { pg: string; 'x-pg-application-name'?: string } Params: { id: string } Body: any }>('/:id(\\d+)', async (request, reply) => { - const connectionString = request.headers.pg + const config = createConnectionConfig(request) const id = Number(request.params.id) - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) - const { data, error } = await pgMeta.policies.update(id, request.body) + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.policies.update(id, request.body as any) await pgMeta.end() if (error) { request.log.error({ error, request: extractRequestForLogging(request) }) @@ -92,15 +103,15 @@ export default async (fastify: FastifyInstance) => { }) fastify.delete<{ - Headers: { pg: string } + Headers: { pg: string; 'x-pg-application-name'?: string } Params: { id: string } }>('/:id(\\d+)', async (request, reply) => { - const connectionString = request.headers.pg + const config = createConnectionConfig(request) const id = Number(request.params.id) - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) + const pgMeta = new PostgresMeta(config) const { data, error } = await pgMeta.policies.remove(id) await pgMeta.end() if (error) { diff --git a/src/server/routes/publications.ts b/src/server/routes/publications.ts index 2c9d7e14..68cf45b2 100644 --- a/src/server/routes/publications.ts +++ b/src/server/routes/publications.ts @@ -1,21 +1,21 @@ import { FastifyInstance } from 'fastify' -import { PostgresMeta } from '../../lib' -import { DEFAULT_POOL_CONFIG } from '../constants' -import { extractRequestForLogging } from '../utils' +import { PostgresMeta } from '../../lib/index.js' +import { createConnectionConfig } from '../utils.js' +import { extractRequestForLogging } from '../utils.js' export default async (fastify: FastifyInstance) => { fastify.get<{ - Headers: { pg: string } + Headers: { pg: string; 'x-pg-application-name'?: string } Querystring: { limit?: number offset?: number } }>('/', async (request, reply) => { - const connectionString = request.headers.pg + const config = createConnectionConfig(request) const limit = request.query.limit const offset = request.query.offset - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) + const pgMeta = new PostgresMeta(config) const { data, error } = await pgMeta.publications.list({ limit, offset }) await pgMeta.end() if (error) { @@ -28,15 +28,15 @@ export default async (fastify: FastifyInstance) => { }) fastify.get<{ - Headers: { pg: string } + Headers: { pg: string; 'x-pg-application-name'?: string } Params: { id: string } }>('/:id(\\d+)', async (request, reply) => { - const connectionString = request.headers.pg + const config = createConnectionConfig(request) const id = Number(request.params.id) - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) + const pgMeta = new PostgresMeta(config) const { data, error } = await pgMeta.publications.retrieve({ id }) await pgMeta.end() if (error) { @@ -49,13 +49,13 @@ export default async (fastify: FastifyInstance) => { }) fastify.post<{ - Headers: { pg: string } + Headers: { pg: string; 'x-pg-application-name'?: string } Body: any }>('/', async (request, reply) => { - const connectionString = request.headers.pg + const config = createConnectionConfig(request) - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) - const { data, error } = await pgMeta.publications.create(request.body) + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.publications.create(request.body as any) await pgMeta.end() if (error) { request.log.error({ error, request: extractRequestForLogging(request) }) @@ -67,17 +67,17 @@ export default async (fastify: FastifyInstance) => { }) fastify.patch<{ - Headers: { pg: string } + Headers: { pg: string; 'x-pg-application-name'?: string } Params: { id: string } Body: any }>('/:id(\\d+)', async (request, reply) => { - const connectionString = request.headers.pg + const config = createConnectionConfig(request) const id = Number(request.params.id) - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) - const { data, error } = await pgMeta.publications.update(id, request.body) + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.publications.update(id, request.body as any) await pgMeta.end() if (error) { request.log.error({ error, request: extractRequestForLogging(request) }) @@ -90,15 +90,15 @@ export default async (fastify: FastifyInstance) => { }) fastify.delete<{ - Headers: { pg: string } + Headers: { pg: string; 'x-pg-application-name'?: string } Params: { id: string } }>('/:id(\\d+)', async (request, reply) => { - const connectionString = request.headers.pg + const config = createConnectionConfig(request) const id = Number(request.params.id) - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) + const pgMeta = new PostgresMeta(config) const { data, error } = await pgMeta.publications.remove(id) await pgMeta.end() if (error) { diff --git a/src/server/routes/query.ts b/src/server/routes/query.ts index 46258377..c8f23bc9 100644 --- a/src/server/routes/query.ts +++ b/src/server/routes/query.ts @@ -1,8 +1,11 @@ import { FastifyInstance, FastifyRequest } from 'fastify' -import { PostgresMeta } from '../../lib' -import * as Parser from '../../lib/Parser' -import { DEFAULT_POOL_CONFIG } from '../constants' -import { extractRequestForLogging, translateErrorToResponseCode } from '../utils' +import { PostgresMeta } from '../../lib/index.js' +import * as Parser from '../../lib/Parser.js' +import { + createConnectionConfig, + extractRequestForLogging, + translateErrorToResponseCode, +} from '../utils.js' const errorOnEmptyQuery = (request: FastifyRequest) => { if (!(request.body as any).query) { @@ -12,34 +15,40 @@ const errorOnEmptyQuery = (request: FastifyRequest) => { export default async (fastify: FastifyInstance) => { fastify.post<{ - Headers: { pg: string } + Headers: { pg: string; 'x-pg-application-name'?: string } Body: { query: string } + Querystring: { + statementTimeoutSecs?: number + } }>('/', async (request, reply) => { + const statementTimeoutSecs = request.query.statementTimeoutSecs errorOnEmptyQuery(request) - const connectionString = request.headers.pg - - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) - const { data, error } = await pgMeta.query(request.body.query) + const config = createConnectionConfig(request) + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.query(request.body.query, { + trackQueryInSentry: true, + statementQueryTimeout: statementTimeoutSecs, + }) await pgMeta.end() if (error) { request.log.error({ error, request: extractRequestForLogging(request) }) reply.code(translateErrorToResponseCode(error)) - return { error: error.message } + return { error: error.formattedError ?? error.message, ...error } } return data || [] }) fastify.post<{ - Headers: { pg: string } + Headers: { pg: string; 'x-pg-application-name'?: string } Body: { query: string } }>('/format', async (request, reply) => { errorOnEmptyQuery(request) - const { data, error } = Parser.Format(request.body.query) + const { data, error } = await Parser.Format(request.body.query) if (error) { request.log.error({ error, request: extractRequestForLogging(request) }) @@ -51,7 +60,7 @@ export default async (fastify: FastifyInstance) => { }) fastify.post<{ - Headers: { pg: string } + Headers: { pg: string; 'x-pg-application-name'?: string } Body: { query: string } @@ -69,7 +78,7 @@ export default async (fastify: FastifyInstance) => { }) fastify.post<{ - Headers: { pg: string } + Headers: { pg: string; 'x-pg-application-name'?: string } Body: { ast: object } diff --git a/src/server/routes/roles.ts b/src/server/routes/roles.ts index e4f231b6..a8809be2 100644 --- a/src/server/routes/roles.ts +++ b/src/server/routes/roles.ts @@ -1,122 +1,236 @@ import { FastifyInstance } from 'fastify' -import { PostgresMeta } from '../../lib' -import { DEFAULT_POOL_CONFIG } from '../constants' -import { extractRequestForLogging } from '../utils' - +import { PostgresMeta } from '../../lib/index.js' +import { createConnectionConfig } from '../utils.js' +import { extractRequestForLogging } from '../utils.js' +import { + PostgresRoleCreate, + PostgresRoleUpdate, + postgresRoleSchema, + postgresRoleCreateSchema, + postgresRoleUpdateSchema, +} from '../../lib/types.js' +import { Type } from '@sinclair/typebox' export default async (fastify: FastifyInstance) => { fastify.get<{ Headers: { pg: string } Querystring: { include_default_roles?: string - include_system_schemas?: string limit?: number offset?: number } - }>('/', async (request, reply) => { - const connectionString = request.headers.pg - const includeDefaultRoles = request.query.include_default_roles === 'true' - const includeSystemSchemas = request.query.include_system_schemas === 'true' - const limit = request.query.limit - const offset = request.query.offset + }>( + '/', + { + schema: { + headers: Type.Object({ + pg: Type.String(), + 'x-pg-application-name': Type.Optional(Type.String()), + }), + querystring: Type.Object({ + include_system_schemas: Type.Optional(Type.String()), + limit: Type.Optional(Type.String()), + offset: Type.Optional(Type.String()), + }), + response: { + 200: Type.Array(postgresRoleSchema), + 500: Type.Object({ + error: Type.String(), + }), + }, + }, + }, + async (request, reply) => { + const config = createConnectionConfig(request) + const includeDefaultRoles = request.query.include_default_roles === 'true' + const limit = request.query.limit + const offset = request.query.offset - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) - const { data, error } = await pgMeta.roles.list({ - includeDefaultRoles, - includeSystemSchemas, - limit, - offset, - }) - await pgMeta.end() - if (error) { - request.log.error({ error, request: extractRequestForLogging(request) }) - reply.code(500) - return { error: error.message } - } + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.roles.list({ + includeDefaultRoles, + limit, + offset, + }) + await pgMeta.end() + if (error) { + request.log.error({ error, request: extractRequestForLogging(request) }) + reply.code(500) + return { error: error.message } + } - return data - }) + return data + } + ) fastify.get<{ Headers: { pg: string } Params: { id: string } - }>('/:id(\\d+)', async (request, reply) => { - const connectionString = request.headers.pg - const id = Number(request.params.id) + }>( + '/:id(\\d+)', + { + schema: { + headers: Type.Object({ + pg: Type.String(), + 'x-pg-application-name': Type.Optional(Type.String()), + }), + params: Type.Object({ + id: Type.RegExp(/\d+/), + }), + response: { + 200: postgresRoleSchema, + 404: Type.Object({ + error: Type.String(), + }), + }, + }, + }, + async (request, reply) => { + const config = createConnectionConfig(request) + const id = Number(request.params.id) - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) - const { data, error } = await pgMeta.roles.retrieve({ id }) - await pgMeta.end() - if (error) { - request.log.error({ error, request: extractRequestForLogging(request) }) - reply.code(404) - return { error: error.message } - } + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.roles.retrieve({ id }) + await pgMeta.end() + if (error) { + request.log.error({ error, request: extractRequestForLogging(request) }) + reply.code(404) + return { error: error.message } + } - return data - }) + return data + } + ) fastify.post<{ Headers: { pg: string } - Body: any - }>('/', async (request, reply) => { - const connectionString = request.headers.pg + Body: PostgresRoleCreate + }>( + '/', + { + schema: { + headers: Type.Object({ + pg: Type.String(), + 'x-pg-application-name': Type.Optional(Type.String()), + }), + body: postgresRoleCreateSchema, + response: { + 200: postgresRoleSchema, + 400: Type.Object({ + error: Type.String(), + }), + }, + }, + }, + async (request, reply) => { + const config = createConnectionConfig(request) - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) - const { data, error } = await pgMeta.roles.create(request.body) - await pgMeta.end() - if (error) { - request.log.error({ error, request: extractRequestForLogging(request) }) - reply.code(400) - return { error: error.message } - } + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.roles.create(request.body) + await pgMeta.end() + if (error) { + request.log.error({ error, request: extractRequestForLogging(request) }) + reply.code(400) + return { error: error.message } + } - return data - }) + return data + } + ) fastify.patch<{ Headers: { pg: string } Params: { id: string } - Body: any - }>('/:id(\\d+)', async (request, reply) => { - const connectionString = request.headers.pg - const id = Number(request.params.id) + Body: PostgresRoleUpdate + }>( + '/:id(\\d+)', + { + schema: { + headers: Type.Object({ + pg: Type.String(), + 'x-pg-application-name': Type.Optional(Type.String()), + }), + params: Type.Object({ + id: Type.RegExp(/\d+/), + }), + body: postgresRoleUpdateSchema, + response: { + 200: postgresRoleSchema, + 400: Type.Object({ + error: Type.String(), + }), + 404: Type.Object({ + error: Type.String(), + }), + }, + }, + }, + async (request, reply) => { + const config = createConnectionConfig(request) + const id = Number(request.params.id) - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) - const { data, error } = await pgMeta.roles.update(id, request.body) - await pgMeta.end() - if (error) { - request.log.error({ error, request: extractRequestForLogging(request) }) - reply.code(400) - if (error.message.startsWith('Cannot find')) reply.code(404) - return { error: error.message } - } + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.roles.update(id, request.body) + await pgMeta.end() + if (error) { + request.log.error({ error, request: extractRequestForLogging(request) }) + reply.code(400) + if (error.message.startsWith('Cannot find')) reply.code(404) + return { error: error.message } + } - return data - }) + return data + } + ) fastify.delete<{ Headers: { pg: string } Params: { id: string } - }>('/:id(\\d+)', async (request, reply) => { - const connectionString = request.headers.pg - const id = Number(request.params.id) + }>( + '/:id(\\d+)', + { + schema: { + headers: Type.Object({ + pg: Type.String(), + 'x-pg-application-name': Type.Optional(Type.String()), + }), + params: Type.Object({ + id: Type.RegExp(/\d+/), + }), + querystring: Type.Object({ + cascade: Type.Optional(Type.String()), + }), + response: { + 200: postgresRoleSchema, + 400: Type.Object({ + error: Type.String(), + }), + 404: Type.Object({ + error: Type.String(), + }), + }, + }, + }, + async (request, reply) => { + const config = createConnectionConfig(request) + const id = Number(request.params.id) - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) - const { data, error } = await pgMeta.roles.remove(id) - await pgMeta.end() - if (error) { - request.log.error({ error, request: extractRequestForLogging(request) }) - reply.code(400) - if (error.message.startsWith('Cannot find')) reply.code(404) - return { error: error.message } - } + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.roles.remove(id) + await pgMeta.end() + if (error) { + request.log.error({ error, request: extractRequestForLogging(request) }) + reply.code(400) + if (error.message.startsWith('Cannot find')) reply.code(404) + return { error: error.message } + } - return data - }) + return data + } + ) } diff --git a/src/server/routes/schemas.ts b/src/server/routes/schemas.ts index e235ba91..a65d104a 100644 --- a/src/server/routes/schemas.ts +++ b/src/server/routes/schemas.ts @@ -1,35 +1,27 @@ +import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' import { Type } from '@sinclair/typebox' -import { FastifyInstance } from 'fastify' -import { PostgresMeta } from '../../lib' +import { PostgresMeta } from '../../lib/index.js' import { - PostgresSchemaCreate, - PostgresSchemaUpdate, postgresSchemaSchema, postgresSchemaCreateSchema, postgresSchemaUpdateSchema, -} from '../../lib/types' -import { DEFAULT_POOL_CONFIG } from '../constants' -import { extractRequestForLogging } from '../utils' +} from '../../lib/types.js' +import { createConnectionConfig } from '../utils.js' +import { extractRequestForLogging } from '../utils.js' -export default async (fastify: FastifyInstance) => { - fastify.get<{ - Headers: { pg: string } - Querystring: { - include_system_schemas?: string - limit?: number - offset?: number - } - }>( +const route: FastifyPluginAsyncTypebox = async (fastify) => { + fastify.get( '/', { schema: { headers: Type.Object({ pg: Type.String(), + 'x-pg-application-name': Type.Optional(Type.String()), }), querystring: Type.Object({ - include_system_schemas: Type.Optional(Type.String()), - limit: Type.Optional(Type.String()), - offset: Type.Optional(Type.String()), + include_system_schemas: Type.Optional(Type.Boolean()), + limit: Type.Optional(Type.Integer()), + offset: Type.Optional(Type.Integer()), }), response: { 200: Type.Array(postgresSchemaSchema), @@ -40,12 +32,12 @@ export default async (fastify: FastifyInstance) => { }, }, async (request, reply) => { - const connectionString = request.headers.pg - const includeSystemSchemas = request.query.include_system_schemas === 'true' + const config = createConnectionConfig(request) + const includeSystemSchemas = request.query.include_system_schemas const limit = request.query.limit const offset = request.query.offset - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) + const pgMeta = new PostgresMeta(config) const { data, error } = await pgMeta.schemas.list({ includeSystemSchemas, limit, offset }) await pgMeta.end() if (error) { @@ -58,20 +50,16 @@ export default async (fastify: FastifyInstance) => { } ) - fastify.get<{ - Headers: { pg: string } - Params: { - id: string - } - }>( + fastify.get( '/:id(\\d+)', { schema: { headers: Type.Object({ pg: Type.String(), + 'x-pg-application-name': Type.Optional(Type.String()), }), params: Type.Object({ - id: Type.RegEx(/\d+/), + id: Type.Integer(), }), response: { 200: postgresSchemaSchema, @@ -82,10 +70,10 @@ export default async (fastify: FastifyInstance) => { }, }, async (request, reply) => { - const connectionString = request.headers.pg - const id = Number(request.params.id) + const config = createConnectionConfig(request) + const id = request.params.id - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) + const pgMeta = new PostgresMeta(config) const { data, error } = await pgMeta.schemas.retrieve({ id }) await pgMeta.end() if (error) { @@ -98,15 +86,13 @@ export default async (fastify: FastifyInstance) => { } ) - fastify.post<{ - Headers: { pg: string } - Body: PostgresSchemaCreate - }>( + fastify.post( '/', { schema: { headers: Type.Object({ pg: Type.String(), + 'x-pg-application-name': Type.Optional(Type.String()), }), body: postgresSchemaCreateSchema, response: { @@ -118,9 +104,9 @@ export default async (fastify: FastifyInstance) => { }, }, async (request, reply) => { - const connectionString = request.headers.pg + const config = createConnectionConfig(request) - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) + const pgMeta = new PostgresMeta(config) const { data, error } = await pgMeta.schemas.create(request.body) await pgMeta.end() if (error) { @@ -133,21 +119,16 @@ export default async (fastify: FastifyInstance) => { } ) - fastify.patch<{ - Headers: { pg: string } - Params: { - id: string - } - Body: PostgresSchemaUpdate - }>( + fastify.patch( '/:id(\\d+)', { schema: { headers: Type.Object({ pg: Type.String(), + 'x-pg-application-name': Type.Optional(Type.String()), }), params: Type.Object({ - id: Type.RegEx(/\d+/), + id: Type.Integer(), }), body: postgresSchemaUpdateSchema, response: { @@ -162,10 +143,10 @@ export default async (fastify: FastifyInstance) => { }, }, async (request, reply) => { - const connectionString = request.headers.pg - const id = Number(request.params.id) + const config = createConnectionConfig(request) + const id = request.params.id - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) + const pgMeta = new PostgresMeta(config) const { data, error } = await pgMeta.schemas.update(id, request.body) await pgMeta.end() if (error) { @@ -179,26 +160,19 @@ export default async (fastify: FastifyInstance) => { } ) - fastify.delete<{ - Headers: { pg: string } - Params: { - id: string - } - Querystring: { - cascade?: string - } - }>( + fastify.delete( '/:id(\\d+)', { schema: { headers: Type.Object({ pg: Type.String(), + 'x-pg-application-name': Type.Optional(Type.String()), }), params: Type.Object({ - id: Type.RegEx(/\d+/), + id: Type.Integer(), }), querystring: Type.Object({ - cascade: Type.Optional(Type.String()), + cascade: Type.Optional(Type.Boolean()), }), response: { 200: postgresSchemaSchema, @@ -212,11 +186,11 @@ export default async (fastify: FastifyInstance) => { }, }, async (request, reply) => { - const connectionString = request.headers.pg - const id = Number(request.params.id) - const cascade = request.query.cascade === 'true' + const config = createConnectionConfig(request) + const id = request.params.id + const cascade = request.query.cascade - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) + const pgMeta = new PostgresMeta(config) const { data, error } = await pgMeta.schemas.remove(id, { cascade }) await pgMeta.end() if (error) { @@ -230,3 +204,4 @@ export default async (fastify: FastifyInstance) => { } ) } +export default route diff --git a/src/server/routes/table-privileges.ts b/src/server/routes/table-privileges.ts new file mode 100644 index 00000000..615d6efa --- /dev/null +++ b/src/server/routes/table-privileges.ts @@ -0,0 +1,134 @@ +import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' +import { Type } from '@sinclair/typebox' +import { PostgresMeta } from '../../lib/index.js' +import { + postgresTablePrivilegesGrantSchema, + postgresTablePrivilegesRevokeSchema, + postgresTablePrivilegesSchema, +} from '../../lib/types.js' +import { createConnectionConfig } from '../utils.js' +import { extractRequestForLogging, translateErrorToResponseCode } from '../utils.js' + +const route: FastifyPluginAsyncTypebox = async (fastify) => { + fastify.get( + '/', + { + schema: { + headers: Type.Object({ + pg: Type.String(), + 'x-pg-application-name': Type.Optional(Type.String()), + }), + querystring: Type.Object({ + include_system_schemas: Type.Optional(Type.Boolean()), + // Note: this only supports comma separated values (e.g., "...?included_schemas=public,core") + included_schemas: Type.Optional(Type.String()), + excluded_schemas: Type.Optional(Type.String()), + limit: Type.Optional(Type.Integer()), + offset: Type.Optional(Type.Integer()), + }), + response: { + 200: Type.Array(postgresTablePrivilegesSchema), + 500: Type.Object({ + error: Type.String(), + }), + }, + }, + }, + async (request, reply) => { + const config = createConnectionConfig(request) + const includeSystemSchemas = request.query.include_system_schemas + const includedSchemas = request.query.included_schemas?.split(',') + const excludedSchemas = request.query.excluded_schemas?.split(',') + const limit = request.query.limit + const offset = request.query.offset + + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.tablePrivileges.list({ + includeSystemSchemas, + includedSchemas, + excludedSchemas, + limit, + offset, + }) + await pgMeta.end() + if (error) { + request.log.error({ error, request: extractRequestForLogging(request) }) + reply.code(translateErrorToResponseCode(error, 500)) + return { error: error.message } + } + + return data + } + ) + + fastify.post( + '/', + { + schema: { + headers: Type.Object({ + pg: Type.String(), + 'x-pg-application-name': Type.Optional(Type.String()), + }), + body: Type.Array(postgresTablePrivilegesGrantSchema), + response: { + 200: Type.Array(postgresTablePrivilegesSchema), + 400: Type.Object({ + error: Type.String(), + }), + }, + }, + }, + async (request, reply) => { + const config = createConnectionConfig(request) + + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.tablePrivileges.grant(request.body) + await pgMeta.end() + if (error) { + request.log.error({ error, request: extractRequestForLogging(request) }) + reply.code(400) + return { error: error.message } + } + + return data + } + ) + + fastify.delete( + '/', + { + schema: { + headers: Type.Object({ + pg: Type.String(), + 'x-pg-application-name': Type.Optional(Type.String()), + }), + body: Type.Array(postgresTablePrivilegesRevokeSchema), + response: { + 200: Type.Array(postgresTablePrivilegesSchema), + 400: Type.Object({ + error: Type.String(), + }), + 404: Type.Object({ + error: Type.String(), + }), + }, + }, + }, + async (request, reply) => { + const config = createConnectionConfig(request) + + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.tablePrivileges.revoke(request.body) + await pgMeta.end() + if (error) { + request.log.error({ error, request: extractRequestForLogging(request) }) + reply.code(400) + if (error.message.startsWith('Cannot find')) reply.code(404) + return { error: error.message } + } + + return data + } + ) +} +export default route diff --git a/src/server/routes/tables.ts b/src/server/routes/tables.ts index 1218d71e..ff5cb2c9 100644 --- a/src/server/routes/tables.ts +++ b/src/server/routes/tables.ts @@ -1,119 +1,223 @@ -import { FastifyInstance } from 'fastify' -import { PostgresMeta } from '../../lib' -import { DEFAULT_POOL_CONFIG } from '../constants' -import { extractRequestForLogging, translateErrorToResponseCode } from '../utils' +import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' +import { Type } from '@sinclair/typebox' +import { PostgresMeta } from '../../lib/index.js' +import { + postgresTableCreateSchema, + postgresTableSchema, + postgresTableUpdateSchema, +} from '../../lib/types.js' +import { + createConnectionConfig, + extractRequestForLogging, + translateErrorToResponseCode, +} from '../utils.js' -export default async (fastify: FastifyInstance) => { - fastify.get<{ - Headers: { pg: string } - Querystring: { - include_system_schemas?: string - limit?: number - offset?: number - } - }>('/', async (request, reply) => { - const connectionString = request.headers.pg - const includeSystemSchemas = request.query.include_system_schemas === 'true' - const limit = request.query.limit - const offset = request.query.offset +const route: FastifyPluginAsyncTypebox = async (fastify) => { + fastify.get( + '/', + { + schema: { + headers: Type.Object({ + pg: Type.String(), + 'x-pg-application-name': Type.Optional(Type.String()), + }), + querystring: Type.Object({ + include_system_schemas: Type.Optional(Type.Boolean()), + // Note: this only supports comma separated values (e.g., ".../tables?included_schemas=public,core") + included_schemas: Type.Optional(Type.String()), + excluded_schemas: Type.Optional(Type.String()), + limit: Type.Optional(Type.Integer()), + offset: Type.Optional(Type.Integer()), + include_columns: Type.Optional(Type.Boolean()), + }), + response: { + 200: Type.Array(postgresTableSchema), + 500: Type.Object({ + error: Type.String(), + }), + }, + }, + }, + async (request, reply) => { + const includeSystemSchemas = request.query.include_system_schemas + const includedSchemas = request.query.included_schemas?.split(',') + const excludedSchemas = request.query.excluded_schemas?.split(',') + const limit = request.query.limit + const offset = request.query.offset + const includeColumns = request.query.include_columns + + const config = createConnectionConfig(request) + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.tables.list({ + includeSystemSchemas, + includedSchemas, + excludedSchemas, + limit, + offset, + includeColumns, + }) + await pgMeta.end() + if (error) { + request.log.error({ error, request: extractRequestForLogging(request) }) + reply.code(translateErrorToResponseCode(error, 500)) + return { error: error.message } + } - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) - const { data, error } = await pgMeta.tables.list({ includeSystemSchemas, limit, offset }) - await pgMeta.end() - if (error) { - request.log.error({ error, request: extractRequestForLogging(request) }) - reply.code(translateErrorToResponseCode(error, 500)) - return { error: error.message } + return data } + ) - return data - }) + fastify.get( + '/:id(\\d+)', + { + schema: { + headers: Type.Object({ + pg: Type.String(), + 'x-pg-application-name': Type.Optional(Type.String()), + }), + params: Type.Object({ + id: Type.Integer(), + }), + response: { + 200: postgresTableSchema, + 404: Type.Object({ + error: Type.String(), + }), + }, + }, + }, + async (request, reply) => { + const id = request.params.id - fastify.get<{ - Headers: { pg: string } - Params: { - id: string - } - }>('/:id(\\d+)', async (request, reply) => { - const connectionString = request.headers.pg - const id = Number(request.params.id) + const config = createConnectionConfig(request) + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.tables.retrieve({ id }) + await pgMeta.end() + if (error) { + request.log.error({ error, request: extractRequestForLogging(request) }) + reply.code(404) + return { error: error.message } + } - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) - const { data, error } = await pgMeta.tables.retrieve({ id }) - await pgMeta.end() - if (error) { - request.log.error({ error, request: extractRequestForLogging(request) }) - reply.code(404) - return { error: error.message } + return data } + ) - return data - }) - - fastify.post<{ - Headers: { pg: string } - Body: any - }>('/', async (request, reply) => { - const connectionString = request.headers.pg + fastify.post( + '/', + { + schema: { + headers: Type.Object({ + pg: Type.String(), + 'x-pg-application-name': Type.Optional(Type.String()), + }), + body: postgresTableCreateSchema, + response: { + 200: postgresTableSchema, + 400: Type.Object({ + error: Type.String(), + }), + }, + }, + }, + async (request, reply) => { + const config = createConnectionConfig(request) + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.tables.create(request.body) + await pgMeta.end() + if (error) { + request.log.error({ error, request: extractRequestForLogging(request) }) + reply.code(400) + return { error: error.message } + } - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) - const { data, error } = await pgMeta.tables.create(request.body) - await pgMeta.end() - if (error) { - request.log.error({ error, request: extractRequestForLogging(request) }) - reply.code(400) - return { error: error.message } + return data } + ) - return data - }) + fastify.patch( + '/:id(\\d+)', + { + schema: { + headers: Type.Object({ + pg: Type.String(), + 'x-pg-application-name': Type.Optional(Type.String()), + }), + params: Type.Object({ + id: Type.Integer(), + }), + body: postgresTableUpdateSchema, + response: { + 200: postgresTableSchema, + 400: Type.Object({ + error: Type.String(), + }), + 404: Type.Object({ + error: Type.String(), + }), + }, + }, + }, + async (request, reply) => { + const id = request.params.id - fastify.patch<{ - Headers: { pg: string } - Params: { - id: string - } - Body: any - }>('/:id(\\d+)', async (request, reply) => { - const connectionString = request.headers.pg - const id = Number(request.params.id) + const config = createConnectionConfig(request) + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.tables.update(id, request.body) + await pgMeta.end() + if (error) { + request.log.error({ error, request: extractRequestForLogging(request) }) + reply.code(400) + if (error.message.startsWith('Cannot find')) reply.code(404) + return { error: error.message } + } - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) - const { data, error } = await pgMeta.tables.update(id, request.body) - await pgMeta.end() - if (error) { - request.log.error({ error, request: extractRequestForLogging(request) }) - reply.code(400) - if (error.message.startsWith('Cannot find')) reply.code(404) - return { error: error.message } + return data } + ) - return data - }) + fastify.delete( + '/:id(\\d+)', + { + schema: { + headers: Type.Object({ + pg: Type.String(), + 'x-pg-application-name': Type.Optional(Type.String()), + }), + params: Type.Object({ + id: Type.Integer(), + }), + querystring: Type.Object({ + cascade: Type.Optional(Type.Boolean()), + }), + response: { + 200: postgresTableSchema, + 400: Type.Object({ + error: Type.String(), + }), + 404: Type.Object({ + error: Type.String(), + }), + }, + }, + }, + async (request, reply) => { + const id = request.params.id + const cascade = request.query.cascade - fastify.delete<{ - Headers: { pg: string } - Params: { - id: string - } - Querystring: { - cascade?: string - } - }>('/:id(\\d+)', async (request, reply) => { - const connectionString = request.headers.pg - const id = Number(request.params.id) - const cascade = request.query.cascade === 'true' + const config = createConnectionConfig(request) + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.tables.remove(id, { cascade }) + await pgMeta.end() + if (error) { + request.log.error({ error, request: extractRequestForLogging(request) }) + reply.code(400) + if (error.message.startsWith('Cannot find')) reply.code(404) + return { error: error.message } + } - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) - const { data, error } = await pgMeta.tables.remove(id, { cascade }) - await pgMeta.end() - if (error) { - request.log.error({ error, request: extractRequestForLogging(request) }) - reply.code(400) - if (error.message.startsWith('Cannot find')) reply.code(404) - return { error: error.message } + return data } - - return data - }) + ) } +export default route diff --git a/src/server/routes/triggers.ts b/src/server/routes/triggers.ts index 9f3cc851..3eb2212a 100644 --- a/src/server/routes/triggers.ts +++ b/src/server/routes/triggers.ts @@ -1,22 +1,35 @@ import { FastifyInstance } from 'fastify' -import { PostgresMeta } from '../../lib' -import { DEFAULT_POOL_CONFIG } from '../constants' -import { extractRequestForLogging } from '../utils' +import { PostgresMeta } from '../../lib/index.js' +import { createConnectionConfig } from '../utils.js' +import { extractRequestForLogging } from '../utils.js' export default async (fastify: FastifyInstance) => { fastify.get<{ - Headers: { pg: string } + Headers: { pg: string; 'x-pg-application-name'?: string } Querystring: { + include_system_schemas?: string + // Note: this only supports comma separated values (e.g., ".../columns?included_schemas=public,core") + included_schemas?: string + excluded_schemas?: string limit?: number offset?: number } }>('/', async (request, reply) => { - const connectionString = request.headers.pg + const config = createConnectionConfig(request) + const includeSystemSchemas = request.query.include_system_schemas === 'true' + const includedSchemas = request.query.included_schemas?.split(',') + const excludedSchemas = request.query.excluded_schemas?.split(',') const limit = request.query.limit const offset = request.query.offset - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) - const { data, error } = await pgMeta.triggers.list({ limit, offset }) + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.triggers.list({ + includeSystemSchemas, + includedSchemas, + excludedSchemas, + limit, + offset, + }) await pgMeta.end() if (error) { request.log.error({ error, request: extractRequestForLogging(request) }) @@ -28,15 +41,15 @@ export default async (fastify: FastifyInstance) => { }) fastify.get<{ - Headers: { pg: string } + Headers: { pg: string; 'x-pg-application-name'?: string } Params: { id: string } }>('/:id(\\d+)', async (request, reply) => { - const connectionString = request.headers.pg + const config = createConnectionConfig(request) const id = Number(request.params.id) - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) + const pgMeta = new PostgresMeta(config) const { data, error } = await pgMeta.triggers.retrieve({ id }) await pgMeta.end() if (error) { @@ -49,13 +62,13 @@ export default async (fastify: FastifyInstance) => { }) fastify.post<{ - Headers: { pg: string } + Headers: { pg: string; 'x-pg-application-name'?: string } Body: any }>('/', async (request, reply) => { - const connectionString = request.headers.pg + const config = createConnectionConfig(request) - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) - const { data, error } = await pgMeta.triggers.create(request.body) + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.triggers.create(request.body as any) await pgMeta.end() if (error) { request.log.error({ error, request: extractRequestForLogging(request) }) @@ -67,17 +80,17 @@ export default async (fastify: FastifyInstance) => { }) fastify.patch<{ - Headers: { pg: string } + Headers: { pg: string; 'x-pg-application-name'?: string } Params: { id: string } Body: any }>('/:id(\\d+)', async (request, reply) => { - const connectionString = request.headers.pg + const config = createConnectionConfig(request) const id = Number(request.params.id) - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) - const { data, error } = await pgMeta.triggers.update(id, request.body) + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.triggers.update(id, request.body as any) await pgMeta.end() if (error) { request.log.error({ error, request: extractRequestForLogging(request) }) @@ -90,7 +103,7 @@ export default async (fastify: FastifyInstance) => { }) fastify.delete<{ - Headers: { pg: string } + Headers: { pg: string; 'x-pg-application-name'?: string } Params: { id: string } @@ -98,11 +111,11 @@ export default async (fastify: FastifyInstance) => { cascade?: string } }>('/:id(\\d+)', async (request, reply) => { - const connectionString = request.headers.pg + const config = createConnectionConfig(request) const id = Number(request.params.id) const cascade = request.query.cascade === 'true' - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) + const pgMeta = new PostgresMeta(config) const { data, error } = await pgMeta.triggers.remove(id, { cascade }) await pgMeta.end() if (error) { diff --git a/src/server/routes/types.ts b/src/server/routes/types.ts index 936a452d..c4e0dfbd 100644 --- a/src/server/routes/types.ts +++ b/src/server/routes/types.ts @@ -1,24 +1,38 @@ import { FastifyInstance } from 'fastify' -import { PostgresMeta } from '../../lib' -import { DEFAULT_POOL_CONFIG } from '../constants' -import { extractRequestForLogging } from '../utils' +import { PostgresMeta } from '../../lib/index.js' +import { createConnectionConfig } from '../utils.js' +import { extractRequestForLogging } from '../utils.js' export default async (fastify: FastifyInstance) => { fastify.get<{ - Headers: { pg: string } + Headers: { pg: string; 'x-pg-application-name'?: string } Querystring: { + include_array_types?: string include_system_schemas?: string + // Note: this only supports comma separated values (e.g., ".../types?included_schemas=public,core") + included_schemas?: string + excluded_schemas?: string limit?: number offset?: number } }>('/', async (request, reply) => { - const connectionString = request.headers.pg + const config = createConnectionConfig(request) + const includeArrayTypes = request.query.include_array_types === 'true' const includeSystemSchemas = request.query.include_system_schemas === 'true' + const includedSchemas = request.query.included_schemas?.split(',') + const excludedSchemas = request.query.excluded_schemas?.split(',') const limit = request.query.limit const offset = request.query.offset - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) - const { data, error } = await pgMeta.types.list({ includeSystemSchemas, limit, offset }) + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.types.list({ + includeArrayTypes, + includeSystemSchemas, + includedSchemas, + excludedSchemas, + limit, + offset, + }) await pgMeta.end() if (error) { request.log.error({ error, request: extractRequestForLogging(request) }) diff --git a/src/server/routes/views.ts b/src/server/routes/views.ts index 51c74049..119088e3 100644 --- a/src/server/routes/views.ts +++ b/src/server/routes/views.ts @@ -1,31 +1,99 @@ -import { FastifyInstance } from 'fastify' -import { PostgresMeta } from '../../lib' -import { DEFAULT_POOL_CONFIG } from '../constants' -import { extractRequestForLogging } from '../utils' +import { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox' +import { Type } from '@sinclair/typebox' +import { PostgresMeta } from '../../lib/index.js' +import { postgresViewSchema } from '../../lib/types.js' +import { createConnectionConfig } from '../utils.js' +import { extractRequestForLogging } from '../utils.js' -export default async (fastify: FastifyInstance) => { - fastify.get<{ - Headers: { pg: string } - Querystring: { - include_system_schemas?: string - limit?: number - offset?: number - } - }>('/', async (request, reply) => { - const connectionString = request.headers.pg - const includeSystemSchemas = request.query.include_system_schemas === 'true' - const limit = request.query.limit - const offset = request.query.offset +const route: FastifyPluginAsyncTypebox = async (fastify) => { + fastify.get( + '/', + { + schema: { + headers: Type.Object({ + pg: Type.String(), + 'x-pg-application-name': Type.Optional(Type.String()), + }), + querystring: Type.Object({ + include_system_schemas: Type.Optional(Type.Boolean()), + // Note: this only supports comma separated values (e.g., ".../views?included_schemas=public,core") + included_schemas: Type.Optional(Type.String()), + excluded_schemas: Type.Optional(Type.String()), + limit: Type.Optional(Type.Integer()), + offset: Type.Optional(Type.Integer()), + include_columns: Type.Optional(Type.Boolean()), + }), + response: { + 200: Type.Array(postgresViewSchema), + 500: Type.Object({ + error: Type.String(), + }), + }, + }, + }, + async (request, reply) => { + const config = createConnectionConfig(request) + const includeSystemSchemas = request.query.include_system_schemas + const includedSchemas = request.query.included_schemas?.split(',') + const excludedSchemas = request.query.excluded_schemas?.split(',') + const limit = request.query.limit + const offset = request.query.offset + const includeColumns = request.query.include_columns + + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.views.list({ + includeSystemSchemas, + includedSchemas, + excludedSchemas, + limit, + offset, + includeColumns, + }) + await pgMeta.end() + if (error) { + request.log.error({ error, request: extractRequestForLogging(request) }) + reply.code(500) + return { error: error.message } + } - const pgMeta = new PostgresMeta({ ...DEFAULT_POOL_CONFIG, connectionString }) - const { data, error } = await pgMeta.views.list({ includeSystemSchemas, limit, offset }) - await pgMeta.end() - if (error) { - request.log.error({ error, request: extractRequestForLogging(request) }) - reply.code(500) - return { error: error.message } + return data } + ) + + fastify.get( + '/:id(\\d+)', + { + schema: { + headers: Type.Object({ + pg: Type.String(), + 'x-pg-application-name': Type.Optional(Type.String()), + }), + params: Type.Object({ + id: Type.Integer(), + }), + response: { + 200: postgresViewSchema, + 404: Type.Object({ + error: Type.String(), + }), + }, + }, + }, + async (request, reply) => { + const config = createConnectionConfig(request) + const id = request.params.id - return data - }) + const pgMeta = new PostgresMeta(config) + const { data, error } = await pgMeta.views.retrieve({ id }) + await pgMeta.end() + if (error) { + request.log.error({ error, request: extractRequestForLogging(request) }) + reply.code(404) + return { error: error.message } + } + + return data + } + ) } +export default route diff --git a/src/server/sentry.ts b/src/server/sentry.ts new file mode 100644 index 00000000..fa50f0a3 --- /dev/null +++ b/src/server/sentry.ts @@ -0,0 +1,50 @@ +import * as Sentry from '@sentry/node' +import { nodeProfilingIntegration } from '@sentry/profiling-node' + +const sentryEnvironment = process.env.ENVIRONMENT ?? 'local' +const dsn = process.env.SENTRY_DSN ?? '' + +const captureOptions: Sentry.NodeOptions = + sentryEnvironment === 'prod' + ? { + // Tracing + tracesSampleRate: 0.00001, // trace 1/10k events + // Set sampling rate for profiling - this is evaluated only once per SDK.init call + profilesSampleRate: 0.00001, // profile 1/10k events + } + : { + tracesSampleRate: 0.01, // trace 1% of the events + profilesSampleRate: 0.01, + } + +const sensitiveKeys = ['pg', 'x-connection-encrypted'] + +function redactSensitiveData(data: any) { + if (data && typeof data === 'object') { + for (const key of sensitiveKeys) { + if (key in data) { + data[key] = '[REDACTED]' + } + } + } +} + +export default Sentry.init({ + enabled: Boolean(dsn), + dsn: dsn, + environment: sentryEnvironment, + integrations: [nodeProfilingIntegration()], + beforeSendTransaction(transaction) { + if (transaction.contexts?.trace?.data) { + redactSensitiveData(transaction.contexts.trace.data) + } + return transaction + }, + beforeSendSpan(span) { + if (span.data) { + redactSensitiveData(span.data) + } + return span + }, + ...captureOptions, +}) diff --git a/src/server/server.ts b/src/server/server.ts new file mode 100644 index 00000000..5396f9e0 --- /dev/null +++ b/src/server/server.ts @@ -0,0 +1,211 @@ +import closeWithGrace from 'close-with-grace' +import { pino } from 'pino' +import { PostgresMeta } from '../lib/index.js' +import { build as buildApp } from './app.js' +import { build as buildAdminApp } from './admin-app.js' +import { + DEFAULT_POOL_CONFIG, + EXPORT_DOCS, + GENERATE_TYPES, + GENERATE_TYPES_DETECT_ONE_TO_ONE_RELATIONSHIPS, + GENERATE_TYPES_INCLUDED_SCHEMAS, + GENERATE_TYPES_SWIFT_ACCESS_CONTROL, + PG_CONNECTION, + PG_META_HOST, + PG_META_PORT, +} from './constants.js' +import { apply as applyTypescriptTemplate } from './templates/typescript.js' +import { apply as applyGoTemplate } from './templates/go.js' +import { apply as applySwiftTemplate } from './templates/swift.js' + +const logger = pino({ + formatters: { + level(label) { + return { level: label } + }, + }, + timestamp: pino.stdTimeFunctions.isoTime, +}) + +const app = buildApp({ logger }) +const adminApp = buildAdminApp({ logger }) + +async function getTypeOutput(): Promise { + const pgMeta: PostgresMeta = new PostgresMeta({ + ...DEFAULT_POOL_CONFIG, + connectionString: PG_CONNECTION, + }) + const [ + { data: schemas, error: schemasError }, + { data: tables, error: tablesError }, + { data: foreignTables, error: foreignTablesError }, + { data: views, error: viewsError }, + { data: materializedViews, error: materializedViewsError }, + { data: columns, error: columnsError }, + { data: relationships, error: relationshipsError }, + { data: functions, error: functionsError }, + { data: types, error: typesError }, + ] = await Promise.all([ + pgMeta.schemas.list(), + pgMeta.tables.list({ + includedSchemas: + GENERATE_TYPES_INCLUDED_SCHEMAS.length > 0 ? GENERATE_TYPES_INCLUDED_SCHEMAS : undefined, + includeColumns: false, + }), + pgMeta.foreignTables.list({ + includedSchemas: + GENERATE_TYPES_INCLUDED_SCHEMAS.length > 0 ? GENERATE_TYPES_INCLUDED_SCHEMAS : undefined, + includeColumns: false, + }), + pgMeta.views.list({ + includedSchemas: + GENERATE_TYPES_INCLUDED_SCHEMAS.length > 0 ? GENERATE_TYPES_INCLUDED_SCHEMAS : undefined, + includeColumns: false, + }), + pgMeta.materializedViews.list({ + includedSchemas: + GENERATE_TYPES_INCLUDED_SCHEMAS.length > 0 ? GENERATE_TYPES_INCLUDED_SCHEMAS : undefined, + includeColumns: false, + }), + pgMeta.columns.list({ + includedSchemas: + GENERATE_TYPES_INCLUDED_SCHEMAS.length > 0 ? GENERATE_TYPES_INCLUDED_SCHEMAS : undefined, + }), + pgMeta.relationships.list(), + pgMeta.functions.list({ + includedSchemas: + GENERATE_TYPES_INCLUDED_SCHEMAS.length > 0 ? GENERATE_TYPES_INCLUDED_SCHEMAS : undefined, + }), + pgMeta.types.list({ + includeTableTypes: true, + includeArrayTypes: true, + includeSystemSchemas: true, + }), + ]) + await pgMeta.end() + + if (schemasError) { + throw new Error(schemasError.message) + } + if (tablesError) { + throw new Error(tablesError.message) + } + if (foreignTablesError) { + throw new Error(foreignTablesError.message) + } + if (viewsError) { + throw new Error(viewsError.message) + } + if (materializedViewsError) { + throw new Error(materializedViewsError.message) + } + if (columnsError) { + throw new Error(columnsError.message) + } + if (relationshipsError) { + throw new Error(relationshipsError.message) + } + if (functionsError) { + throw new Error(functionsError.message) + } + if (typesError) { + throw new Error(typesError.message) + } + + const config = { + schemas: schemas!.filter( + ({ name }) => + GENERATE_TYPES_INCLUDED_SCHEMAS.length === 0 || + GENERATE_TYPES_INCLUDED_SCHEMAS.includes(name) + ), + tables: tables!, + foreignTables: foreignTables!, + views: views!, + materializedViews: materializedViews!, + columns: columns!, + relationships: relationships!, + functions: functions!.filter( + ({ return_type }) => !['trigger', 'event_trigger'].includes(return_type) + ), + types: types!, + detectOneToOneRelationships: GENERATE_TYPES_DETECT_ONE_TO_ONE_RELATIONSHIPS, + } + + switch (GENERATE_TYPES?.toLowerCase()) { + case 'typescript': + return await applyTypescriptTemplate(config) + case 'swift': + return await applySwiftTemplate({ + ...config, + accessControl: GENERATE_TYPES_SWIFT_ACCESS_CONTROL, + }) + case 'go': + return applyGoTemplate(config) + default: + throw new Error(`Unsupported language for GENERATE_TYPES: ${GENERATE_TYPES}`) + } +} + +if (EXPORT_DOCS) { + // TODO: Move to a separate script. + await app.ready() + // @ts-ignore: app.swagger() is a Fastify decorator, so doesn't show up in the types + console.log(JSON.stringify(app.swagger(), null, 2)) +} else if (GENERATE_TYPES) { + console.log(await getTypeOutput()) +} else { + const closeListeners = closeWithGrace(async ({ err, signal, manual }) => { + if (err) { + app.log.error({ err }, 'server closing with error') + } else { + app.log.error( + { err: new Error('Signal Received') }, + `${signal} signal received, server closing, close manual received: ${manual}` + ) + } + try { + await app.close() + } catch (err) { + app.log.error({ err }, `Failed to close app`) + throw err + } + try { + await adminApp.close() + } catch (err) { + app.log.error({ err }, `Failed to close adminApp`) + throw err + } + }) + app.addHook('onClose', async () => { + try { + closeListeners.uninstall() + await adminApp.close() + } catch (err) { + app.log.error({ err }, `Failed to close adminApp in app onClose hook`) + throw err + } + }) + adminApp.addHook('onClose', async () => { + try { + closeListeners.uninstall() + await app.close() + } catch (err) { + app.log.error({ err }, `Failed to close app in adminApp onClose hook`) + throw err + } + }) + + app.listen({ port: PG_META_PORT, host: PG_META_HOST }, (err) => { + if (err) { + app.log.error({ err }, 'Uncaught error in app, exit(1)') + process.exit(1) + } + const adminPort = PG_META_PORT + 1 + adminApp.listen({ port: adminPort, host: PG_META_HOST }, (err) => { + if (err) { + app.log.error({ err }, 'Uncaught error in adminApp, exit(1)') + process.exit(1) + } + }) + }) +} diff --git a/src/server/templates/go.ts b/src/server/templates/go.ts new file mode 100644 index 00000000..46fd5d82 --- /dev/null +++ b/src/server/templates/go.ts @@ -0,0 +1,323 @@ +import type { + PostgresColumn, + PostgresMaterializedView, + PostgresSchema, + PostgresTable, + PostgresType, + PostgresView, +} from '../../lib/index.js' +import type { GeneratorMetadata } from '../../lib/generators.js' + +type Operation = 'Select' | 'Insert' | 'Update' + +export const apply = ({ + schemas, + tables, + views, + materializedViews, + columns, + types, +}: GeneratorMetadata): string => { + const columnsByTableId = columns + .sort(({ name: a }, { name: b }) => a.localeCompare(b)) + .reduce( + (acc, curr) => { + acc[curr.table_id] ??= [] + acc[curr.table_id].push(curr) + return acc + }, + {} as Record + ) + + const compositeTypes = types.filter((type) => type.attributes.length > 0) + + let output = ` +package database + +${tables + .filter((table) => schemas.some((schema) => schema.name === table.schema)) + .flatMap((table) => + generateTableStructsForOperations( + schemas.find((schema) => schema.name === table.schema)!, + table, + columnsByTableId[table.id], + types, + ['Select', 'Insert', 'Update'] + ) + ) + .join('\n\n')} + +${views + .filter((view) => schemas.some((schema) => schema.name === view.schema)) + .flatMap((view) => + generateTableStructsForOperations( + schemas.find((schema) => schema.name === view.schema)!, + view, + columnsByTableId[view.id], + types, + ['Select'] + ) + ) + .join('\n\n')} + +${materializedViews + .filter((materializedView) => schemas.some((schema) => schema.name === materializedView.schema)) + .flatMap((materializedView) => + generateTableStructsForOperations( + schemas.find((schema) => schema.name === materializedView.schema)!, + materializedView, + columnsByTableId[materializedView.id], + types, + ['Select'] + ) + ) + .join('\n\n')} + +${compositeTypes + .filter((compositeType) => schemas.some((schema) => schema.name === compositeType.schema)) + .map((compositeType) => + generateCompositeTypeStruct( + schemas.find((schema) => schema.name === compositeType.schema)!, + compositeType, + types + ) + ) + .join('\n\n')} +`.trim() + + return output +} + +/** + * Converts a Postgres name to PascalCase. + * + * @example + * ```ts + * formatForGoTypeName('pokedex') // Pokedex + * formatForGoTypeName('pokemon_center') // PokemonCenter + * formatForGoTypeName('victory-road') // VictoryRoad + * formatForGoTypeName('pokemon league') // PokemonLeague + * ``` + */ +function formatForGoTypeName(name: string): string { + return name + .split(/[^a-zA-Z0-9]/) + .map((word) => `${word[0].toUpperCase()}${word.slice(1)}`) + .join('') +} + +function generateTableStruct( + schema: PostgresSchema, + table: PostgresTable | PostgresView | PostgresMaterializedView, + columns: PostgresColumn[] | undefined, + types: PostgresType[], + operation: Operation +): string { + // Storing columns as a tuple of [formattedName, type, name] rather than creating the string + // representation of the line allows us to pre-format the entries. Go formats + // struct fields to be aligned, e.g.: + // ```go + // type Pokemon struct { + // id int `json:"id"` + // name string `json:"name"` + // } + const columnEntries: [string, string, string][] = + columns?.map((column) => { + let nullable: boolean + if (operation === 'Insert') { + nullable = + column.is_nullable || column.is_identity || column.is_generated || !!column.default_value + } else if (operation === 'Update') { + nullable = true + } else { + nullable = column.is_nullable + } + return [ + formatForGoTypeName(column.name), + pgTypeToGoType(column.format, nullable, types), + column.name, + ] + }) ?? [] + + const [maxFormattedNameLength, maxTypeLength] = columnEntries.reduce( + ([maxFormattedName, maxType], [formattedName, type]) => { + return [Math.max(maxFormattedName, formattedName.length), Math.max(maxType, type.length)] + }, + [0, 0] + ) + + // Pad the formatted name and type to align the struct fields, then join + // create the final string representation of the struct fields. + const formattedColumnEntries = columnEntries.map(([formattedName, type, name]) => { + return ` ${formattedName.padEnd(maxFormattedNameLength)} ${type.padEnd( + maxTypeLength + )} \`json:"${name}"\`` + }) + + return ` +type ${formatForGoTypeName(schema.name)}${formatForGoTypeName(table.name)}${operation} struct { +${formattedColumnEntries.join('\n')} +} +`.trim() +} + +function generateTableStructsForOperations( + schema: PostgresSchema, + table: PostgresTable | PostgresView | PostgresMaterializedView, + columns: PostgresColumn[] | undefined, + types: PostgresType[], + operations: Operation[] +): string[] { + return operations.map((operation) => + generateTableStruct(schema, table, columns, types, operation) + ) +} + +function generateCompositeTypeStruct( + schema: PostgresSchema, + type: PostgresType, + types: PostgresType[] +): string { + // Use the type_id of the attributes to find the types of the attributes + const typeWithRetrievedAttributes = { + ...type, + attributes: type.attributes.map((attribute) => { + const type = types.find((type) => type.id === attribute.type_id) + return { + ...attribute, + type, + } + }), + } + const attributeEntries: [string, string, string][] = typeWithRetrievedAttributes.attributes.map( + (attribute) => [ + formatForGoTypeName(attribute.name), + pgTypeToGoType(attribute.type!.format, false), + attribute.name, + ] + ) + + const [maxFormattedNameLength, maxTypeLength] = attributeEntries.reduce( + ([maxFormattedName, maxType], [formattedName, type]) => { + return [Math.max(maxFormattedName, formattedName.length), Math.max(maxType, type.length)] + }, + [0, 0] + ) + + // Pad the formatted name and type to align the struct fields, then join + // create the final string representation of the struct fields. + const formattedAttributeEntries = attributeEntries.map(([formattedName, type, name]) => { + return ` ${formattedName.padEnd(maxFormattedNameLength)} ${type.padEnd( + maxTypeLength + )} \`json:"${name}"\`` + }) + + return ` +type ${formatForGoTypeName(schema.name)}${formatForGoTypeName(type.name)} struct { +${formattedAttributeEntries.join('\n')} +} +`.trim() +} + +// Note: the type map uses `interface{ } `, not `any`, to remain compatible with +// older versions of Go. +const GO_TYPE_MAP = { + // Bool + bool: 'bool', + + // Numbers + int2: 'int16', + int4: 'int32', + int8: 'int64', + float4: 'float32', + float8: 'float64', + numeric: 'float64', + + // Strings + bytea: '[]byte', + bpchar: 'string', + varchar: 'string', + date: 'string', + text: 'string', + citext: 'string', + time: 'string', + timetz: 'string', + timestamp: 'string', + timestamptz: 'string', + uuid: 'string', + vector: 'string', + + // JSON + json: 'interface{}', + jsonb: 'interface{}', + + // Range + int4range: 'string', + int4multirange: 'string', + int8range: 'string', + int8multirange: 'string', + numrange: 'string', + nummultirange: 'string', + tsrange: 'string', + tsmultirange: 'string', + tstzrange: 'string', + tstzmultirange: 'string', + daterange: 'string', + datemultirange: 'string', + + // Misc + void: 'interface{}', + record: 'map[string]interface{}', +} as const + +type GoType = (typeof GO_TYPE_MAP)[keyof typeof GO_TYPE_MAP] + +const GO_NULLABLE_TYPE_MAP: Record = { + string: '*string', + bool: '*bool', + int16: '*int16', + int32: '*int32', + int64: '*int64', + float32: '*float32', + float64: '*float64', + '[]byte': '[]byte', + 'interface{}': 'interface{}', + 'map[string]interface{}': 'map[string]interface{}', +} + +function pgTypeToGoType(pgType: string, nullable: boolean, types: PostgresType[] = []): string { + let goType: GoType | undefined = undefined + if (pgType in GO_TYPE_MAP) { + goType = GO_TYPE_MAP[pgType as keyof typeof GO_TYPE_MAP] + } + + // Enums + const enumType = types.find((type) => type.name === pgType && type.enums.length > 0) + if (enumType) { + goType = 'string' + } + + if (goType) { + if (nullable) { + return GO_NULLABLE_TYPE_MAP[goType] + } + return goType + } + + // Composite types + const compositeType = types.find((type) => type.name === pgType && type.attributes.length > 0) + if (compositeType) { + // TODO: generate composite types + // return formatForGoTypeName(pgType) + return 'map[string]interface{}' + } + + // Arrays + if (pgType.startsWith('_')) { + const innerType = pgTypeToGoType(pgType.slice(1), nullable) + return `[]${innerType} ` + } + + // Fallback + return 'interface{}' +} diff --git a/src/server/templates/swift.ts b/src/server/templates/swift.ts new file mode 100644 index 00000000..fee24297 --- /dev/null +++ b/src/server/templates/swift.ts @@ -0,0 +1,418 @@ +import prettier from 'prettier' +import type { + PostgresColumn, + PostgresFunction, + PostgresMaterializedView, + PostgresSchema, + PostgresTable, + PostgresType, + PostgresView, +} from '../../lib/index.js' +import type { GeneratorMetadata } from '../../lib/generators.js' +import { PostgresForeignTable } from '../../lib/types.js' + +type Operation = 'Select' | 'Insert' | 'Update' +export type AccessControl = 'internal' | 'public' | 'private' | 'package' + +type SwiftGeneratorOptions = { + accessControl: AccessControl +} + +type SwiftEnumCase = { + formattedName: string + rawValue: string +} + +type SwiftEnum = { + formattedEnumName: string + protocolConformances: string[] + cases: SwiftEnumCase[] +} + +type SwiftAttribute = { + formattedAttributeName: string + formattedType: string + rawName: string + isIdentity: boolean +} + +type SwiftStruct = { + formattedStructName: string + protocolConformances: string[] + attributes: SwiftAttribute[] + codingKeysEnum: SwiftEnum | undefined +} + +function formatForSwiftSchemaName(schema: string): string { + return `${formatForSwiftTypeName(schema)}Schema` +} + +function pgEnumToSwiftEnum(pgEnum: PostgresType): SwiftEnum { + return { + formattedEnumName: formatForSwiftTypeName(pgEnum.name), + protocolConformances: ['String', 'Codable', 'Hashable', 'Sendable'], + cases: pgEnum.enums.map((case_) => { + return { formattedName: formatForSwiftPropertyName(case_), rawValue: case_ } + }), + } +} + +function pgTypeToSwiftStruct( + table: PostgresTable | PostgresForeignTable | PostgresView | PostgresMaterializedView, + columns: PostgresColumn[] | undefined, + operation: Operation, + { + types, + views, + tables, + }: { types: PostgresType[]; views: PostgresView[]; tables: PostgresTable[] } +): SwiftStruct { + const columnEntries: SwiftAttribute[] = + columns?.map((column) => { + let nullable: boolean + + if (operation === 'Insert') { + nullable = + column.is_nullable || column.is_identity || column.is_generated || !!column.default_value + } else if (operation === 'Update') { + nullable = true + } else { + nullable = column.is_nullable + } + + return { + rawName: column.name, + formattedAttributeName: formatForSwiftPropertyName(column.name), + formattedType: pgTypeToSwiftType(column.format, nullable, { types, views, tables }), + isIdentity: column.is_identity, + } + }) ?? [] + + return { + formattedStructName: `${formatForSwiftTypeName(table.name)}${operation}`, + attributes: columnEntries, + protocolConformances: ['Codable', 'Hashable', 'Sendable'], + codingKeysEnum: generateCodingKeysEnumFromAttributes(columnEntries), + } +} + +function generateCodingKeysEnumFromAttributes(attributes: SwiftAttribute[]): SwiftEnum | undefined { + return attributes.length > 0 + ? { + formattedEnumName: 'CodingKeys', + protocolConformances: ['String', 'CodingKey'], + cases: attributes.map((attribute) => { + return { + formattedName: attribute.formattedAttributeName, + rawValue: attribute.rawName, + } + }), + } + : undefined +} + +function pgCompositeTypeToSwiftStruct( + type: PostgresType, + { + types, + views, + tables, + }: { types: PostgresType[]; views: PostgresView[]; tables: PostgresTable[] } +): SwiftStruct { + const typeWithRetrievedAttributes = { + ...type, + attributes: type.attributes.map((attribute) => { + const type = types.find((type) => type.id === attribute.type_id) + return { + ...attribute, + type, + } + }), + } + + const attributeEntries: SwiftAttribute[] = typeWithRetrievedAttributes.attributes.map( + (attribute) => { + return { + formattedAttributeName: formatForSwiftTypeName(attribute.name), + formattedType: pgTypeToSwiftType(attribute.type!.format, false, { types, views, tables }), + rawName: attribute.name, + isIdentity: false, + } + } + ) + + return { + formattedStructName: formatForSwiftTypeName(type.name), + attributes: attributeEntries, + protocolConformances: ['Codable', 'Hashable', 'Sendable'], + codingKeysEnum: generateCodingKeysEnumFromAttributes(attributeEntries), + } +} + +function generateProtocolConformances(protocols: string[]): string { + return protocols.length === 0 ? '' : `: ${protocols.join(', ')}` +} + +function generateEnum( + enum_: SwiftEnum, + { accessControl, level }: SwiftGeneratorOptions & { level: number } +): string[] { + return [ + `${ident(level)}${accessControl} enum ${enum_.formattedEnumName}${generateProtocolConformances(enum_.protocolConformances)} {`, + ...enum_.cases.map( + (case_) => `${ident(level + 1)}case ${case_.formattedName} = "${case_.rawValue}"` + ), + `${ident(level)}}`, + ] +} + +function generateStruct( + struct: SwiftStruct, + { accessControl, level }: SwiftGeneratorOptions & { level: number } +): string[] { + const identity = struct.attributes.find((column) => column.isIdentity) + + let protocolConformances = struct.protocolConformances + if (identity) { + protocolConformances.push('Identifiable') + } + + let output = [ + `${ident(level)}${accessControl} struct ${struct.formattedStructName}${generateProtocolConformances(struct.protocolConformances)} {`, + ] + + if (identity && identity.formattedAttributeName !== 'id') { + output.push( + `${ident(level + 1)}${accessControl} var id: ${identity.formattedType} { ${identity.formattedAttributeName} }` + ) + } + + output.push( + ...struct.attributes.map( + (attribute) => + `${ident(level + 1)}${accessControl} let ${attribute.formattedAttributeName}: ${attribute.formattedType}` + ) + ) + + if (struct.codingKeysEnum) { + output.push(...generateEnum(struct.codingKeysEnum, { accessControl, level: level + 1 })) + } + + output.push(`${ident(level)}}`) + + return output +} + +export const apply = async ({ + schemas, + tables, + foreignTables, + views, + materializedViews, + columns, + types, + accessControl, +}: GeneratorMetadata & SwiftGeneratorOptions): Promise => { + const columnsByTableId = Object.fromEntries( + [...tables, ...foreignTables, ...views, ...materializedViews].map((t) => [t.id, []]) + ) + + columns + .filter((c) => c.table_id in columnsByTableId) + .sort(({ name: a }, { name: b }) => a.localeCompare(b)) + .forEach((c) => columnsByTableId[c.table_id].push(c)) + + let output = [ + 'import Foundation', + 'import Supabase', + '', + ...schemas + .sort(({ name: a }, { name: b }) => a.localeCompare(b)) + .flatMap((schema) => { + const schemaTables = [...tables, ...foreignTables] + .filter((table) => table.schema === schema.name) + .sort(({ name: a }, { name: b }) => a.localeCompare(b)) + + const schemaViews = [...views, ...materializedViews] + .filter((table) => table.schema === schema.name) + .sort(({ name: a }, { name: b }) => a.localeCompare(b)) + + const schemaEnums = types + .filter((type) => type.schema === schema.name && type.enums.length > 0) + .sort(({ name: a }, { name: b }) => a.localeCompare(b)) + + const schemaCompositeTypes = types + .filter((type) => type.schema === schema.name && type.attributes.length > 0) + .sort(({ name: a }, { name: b }) => a.localeCompare(b)) + + return [ + `${accessControl} enum ${formatForSwiftSchemaName(schema.name)} {`, + ...schemaEnums.flatMap((enum_) => + generateEnum(pgEnumToSwiftEnum(enum_), { accessControl, level: 1 }) + ), + ...schemaTables.flatMap((table) => + (['Select', 'Insert', 'Update'] as Operation[]) + .map((operation) => + pgTypeToSwiftStruct(table, columnsByTableId[table.id], operation, { + types, + views, + tables, + }) + ) + .flatMap((struct) => generateStruct(struct, { accessControl, level: 1 })) + ), + ...schemaViews.flatMap((view) => + generateStruct( + pgTypeToSwiftStruct(view, columnsByTableId[view.id], 'Select', { + types, + views, + tables, + }), + { accessControl, level: 1 } + ) + ), + ...schemaCompositeTypes.flatMap((type) => + generateStruct(pgCompositeTypeToSwiftStruct(type, { types, views, tables }), { + accessControl, + level: 1, + }) + ), + '}', + ] + }), + ] + + return output.join('\n') +} + +// TODO: Make this more robust. Currently doesn't handle range types - returns them as string. +const pgTypeToSwiftType = ( + pgType: string, + nullable: boolean, + { + types, + views, + tables, + }: { types: PostgresType[]; views: PostgresView[]; tables: PostgresTable[] } +): string => { + let swiftType: string + + if (pgType === 'bool') { + swiftType = 'Bool' + } else if (pgType === 'int2') { + swiftType = 'Int16' + } else if (pgType === 'int4') { + swiftType = 'Int32' + } else if (pgType === 'int8') { + swiftType = 'Int64' + } else if (pgType === 'float4') { + swiftType = 'Float' + } else if (pgType === 'float8') { + swiftType = 'Double' + } else if (pgType === 'uuid') { + swiftType = 'UUID' + } else if ( + [ + 'bytea', + 'bpchar', + 'varchar', + 'date', + 'text', + 'citext', + 'time', + 'timetz', + 'timestamp', + 'timestamptz', + 'vector', + ].includes(pgType) + ) { + swiftType = 'String' + } else if (['json', 'jsonb'].includes(pgType)) { + swiftType = 'AnyJSON' + } else if (pgType === 'void') { + swiftType = 'Void' + } else if (pgType === 'record') { + swiftType = 'JSONObject' + } else if (pgType.startsWith('_')) { + swiftType = `[${pgTypeToSwiftType(pgType.substring(1), false, { types, views, tables })}]` + } else { + const enumType = types.find((type) => type.name === pgType && type.enums.length > 0) + + const compositeTypes = [...types, ...views, ...tables].find((type) => type.name === pgType) + + if (enumType) { + swiftType = `${formatForSwiftTypeName(enumType.name)}` + } else if (compositeTypes) { + // Append a `Select` to the composite type, as that is how is named in the generated struct. + swiftType = `${formatForSwiftTypeName(compositeTypes.name)}Select` + } else { + swiftType = 'AnyJSON' + } + } + + return `${swiftType}${nullable ? '?' : ''}` +} + +function ident(level: number, options: { width: number } = { width: 2 }): string { + return ' '.repeat(level * options.width) +} + +/** + * Converts a Postgres name to PascalCase. + * + * @example + * ```ts + * formatForSwiftTypeName('pokedex') // Pokedex + * formatForSwiftTypeName('pokemon_center') // PokemonCenter + * formatForSwiftTypeName('victory-road') // VictoryRoad + * formatForSwiftTypeName('pokemon league') // PokemonLeague + * formatForSwiftTypeName('_key_id_context') // _KeyIdContext + * ``` + */ +function formatForSwiftTypeName(name: string): string { + // Preserve the initial underscore if it exists + let prefix = '' + if (name.startsWith('_')) { + prefix = '_' + name = name.slice(1) // Remove the initial underscore for processing + } + + return ( + prefix + + name + .split(/[^a-zA-Z0-9]+/) + .map((word) => { + if (word) { + return `${word[0].toUpperCase()}${word.slice(1)}` + } else { + return '' + } + }) + .join('') + ) +} + +const SWIFT_KEYWORDS = ['in', 'default'] + +/** + * Converts a Postgres name to pascalCase. + * + * @example + * ```ts + * formatForSwiftTypeName('pokedex') // pokedex + * formatForSwiftTypeName('pokemon_center') // pokemonCenter + * formatForSwiftTypeName('victory-road') // victoryRoad + * formatForSwiftTypeName('pokemon league') // pokemonLeague + * ``` + */ +function formatForSwiftPropertyName(name: string): string { + const propertyName = name + .split(/[^a-zA-Z0-9]/) + .map((word, index) => { + const lowerWord = word.toLowerCase() + return index !== 0 ? lowerWord.charAt(0).toUpperCase() + lowerWord.slice(1) : lowerWord + }) + .join('') + + return SWIFT_KEYWORDS.includes(propertyName) ? `\`${propertyName}\`` : propertyName +} diff --git a/src/server/templates/typescript.ts b/src/server/templates/typescript.ts new file mode 100644 index 00000000..6e3fc750 --- /dev/null +++ b/src/server/templates/typescript.ts @@ -0,0 +1,671 @@ +import prettier from 'prettier' +import type { + PostgresColumn, + PostgresFunction, + PostgresSchema, + PostgresTable, + PostgresType, + PostgresView, +} from '../../lib/index.js' +import type { GeneratorMetadata } from '../../lib/generators.js' +import { GENERATE_TYPES_DEFAULT_SCHEMA } from '../constants.js' + +export const apply = async ({ + schemas, + tables, + foreignTables, + views, + materializedViews, + columns, + relationships, + functions, + types, + detectOneToOneRelationships, +}: GeneratorMetadata & { + detectOneToOneRelationships: boolean +}): Promise => { + const columnsByTableId = Object.fromEntries( + [...tables, ...foreignTables, ...views, ...materializedViews].map((t) => [t.id, []]) + ) + columns + .filter((c) => c.table_id in columnsByTableId) + .sort(({ name: a }, { name: b }) => a.localeCompare(b)) + .forEach((c) => columnsByTableId[c.table_id].push(c)) + + let output = ` +export type Json = string | number | boolean | null | { [key: string]: Json | undefined } | Json[] + +export type Database = { + ${schemas + .sort(({ name: a }, { name: b }) => a.localeCompare(b)) + .map((schema) => { + const schemaTables = [...tables, ...foreignTables] + .filter((table) => table.schema === schema.name) + .sort(({ name: a }, { name: b }) => a.localeCompare(b)) + const schemaViews = [...views, ...materializedViews] + .filter((view) => view.schema === schema.name) + .sort(({ name: a }, { name: b }) => a.localeCompare(b)) + const schemaFunctions = functions + .filter((func) => { + if (func.schema !== schema.name) { + return false + } + + // Either: + // 1. All input args are be named, or + // 2. There is only one input arg which is unnamed + const inArgs = func.args.filter(({ mode }) => ['in', 'inout', 'variadic'].includes(mode)) + + if (!inArgs.some(({ name }) => name === '')) { + return true + } + + if (inArgs.length === 1) { + return true + } + + return false + }) + .sort(({ name: a }, { name: b }) => a.localeCompare(b)) + const schemaEnums = types + .filter((type) => type.schema === schema.name && type.enums.length > 0) + .sort(({ name: a }, { name: b }) => a.localeCompare(b)) + const schemaCompositeTypes = types + .filter((type) => type.schema === schema.name && type.attributes.length > 0) + .sort(({ name: a }, { name: b }) => a.localeCompare(b)) + return `${JSON.stringify(schema.name)}: { + Tables: { + ${ + schemaTables.length === 0 + ? '[_ in never]: never' + : schemaTables.map( + (table) => `${JSON.stringify(table.name)}: { + Row: { + ${[ + ...columnsByTableId[table.id].map( + (column) => + `${JSON.stringify(column.name)}: ${pgTypeToTsType(schema, column.format, { + types, + schemas, + tables, + views, + })} ${column.is_nullable ? '| null' : ''}` + ), + ...schemaFunctions + .filter((fn) => fn.argument_types === table.name) + .map((fn) => { + const type = types.find(({ id }) => id === fn.return_type_id) + let tsType = 'unknown' + if (type) { + tsType = pgTypeToTsType(schema, type.name, { + types, + schemas, + tables, + views, + }) + } + return `${JSON.stringify(fn.name)}: ${tsType} | null` + }), + ]} + } + Insert: { + ${columnsByTableId[table.id].map((column) => { + let output = JSON.stringify(column.name) + + if (column.identity_generation === 'ALWAYS') { + return `${output}?: never` + } + + if ( + column.is_nullable || + column.is_identity || + column.default_value !== null + ) { + output += '?:' + } else { + output += ':' + } + + output += pgTypeToTsType(schema, column.format, { + types, + schemas, + tables, + views, + }) + + if (column.is_nullable) { + output += '| null' + } + + return output + })} + } + Update: { + ${columnsByTableId[table.id].map((column) => { + let output = JSON.stringify(column.name) + + if (column.identity_generation === 'ALWAYS') { + return `${output}?: never` + } + + output += `?: ${pgTypeToTsType(schema, column.format, { + types, + schemas, + tables, + views, + })}` + + if (column.is_nullable) { + output += '| null' + } + + return output + })} + } + Relationships: [ + ${relationships + .filter( + (relationship) => + relationship.schema === table.schema && + relationship.referenced_schema === table.schema && + relationship.relation === table.name + ) + .sort( + (a, b) => + a.foreign_key_name.localeCompare(b.foreign_key_name) || + a.referenced_relation.localeCompare(b.referenced_relation) || + JSON.stringify(a.referenced_columns).localeCompare( + JSON.stringify(b.referenced_columns) + ) + ) + .map( + (relationship) => `{ + foreignKeyName: ${JSON.stringify(relationship.foreign_key_name)} + columns: ${JSON.stringify(relationship.columns)} + ${ + detectOneToOneRelationships + ? `isOneToOne: ${relationship.is_one_to_one};` + : '' + }referencedRelation: ${JSON.stringify(relationship.referenced_relation)} + referencedColumns: ${JSON.stringify(relationship.referenced_columns)} + }` + )} + ] + }` + ) + } + } + Views: { + ${ + schemaViews.length === 0 + ? '[_ in never]: never' + : schemaViews.map( + (view) => `${JSON.stringify(view.name)}: { + Row: { + ${columnsByTableId[view.id].map( + (column) => + `${JSON.stringify(column.name)}: ${pgTypeToTsType(schema, column.format, { + types, + schemas, + tables, + views, + })} ${column.is_nullable ? '| null' : ''}` + )} + } + ${ + 'is_updatable' in view && view.is_updatable + ? `Insert: { + ${columnsByTableId[view.id].map((column) => { + let output = JSON.stringify(column.name) + + if (!column.is_updatable) { + return `${output}?: never` + } + + output += `?: ${pgTypeToTsType(schema, column.format, { + types, + schemas, + tables, + views, + })} | null` + + return output + })} + } + Update: { + ${columnsByTableId[view.id].map((column) => { + let output = JSON.stringify(column.name) + + if (!column.is_updatable) { + return `${output}?: never` + } + + output += `?: ${pgTypeToTsType(schema, column.format, { + types, + schemas, + tables, + views, + })} | null` + + return output + })} + } + ` + : '' + }Relationships: [ + ${relationships + .filter( + (relationship) => + relationship.schema === view.schema && + relationship.referenced_schema === view.schema && + relationship.relation === view.name + ) + .sort( + (a, b) => + a.foreign_key_name.localeCompare(b.foreign_key_name) || + a.referenced_relation.localeCompare(b.referenced_relation) || + JSON.stringify(a.referenced_columns).localeCompare( + JSON.stringify(b.referenced_columns) + ) + ) + .map( + (relationship) => `{ + foreignKeyName: ${JSON.stringify(relationship.foreign_key_name)} + columns: ${JSON.stringify(relationship.columns)} + ${ + detectOneToOneRelationships + ? `isOneToOne: ${relationship.is_one_to_one};` + : '' + }referencedRelation: ${JSON.stringify(relationship.referenced_relation)} + referencedColumns: ${JSON.stringify(relationship.referenced_columns)} + }` + )} + ] + }` + ) + } + } + Functions: { + ${(() => { + if (schemaFunctions.length === 0) { + return '[_ in never]: never' + } + + const schemaFunctionsGroupedByName = schemaFunctions.reduce( + (acc, curr) => { + acc[curr.name] ??= [] + acc[curr.name].push(curr) + return acc + }, + {} as Record + ) + + return Object.entries(schemaFunctionsGroupedByName).map( + ([fnName, fns]) => + `${JSON.stringify(fnName)}: { + Args: ${fns + .map(({ args }) => { + const inArgs = args.filter(({ mode }) => mode === 'in') + + if (inArgs.length === 0) { + return 'Record' + } + + const argsNameAndType = inArgs.map(({ name, type_id, has_default }) => { + const type = types.find(({ id }) => id === type_id) + let tsType = 'unknown' + if (type) { + tsType = pgTypeToTsType(schema, type.name, { + types, + schemas, + tables, + views, + }) + } + return { name, type: tsType, has_default } + }) + return `{ ${argsNameAndType.map(({ name, type, has_default }) => `${JSON.stringify(name)}${has_default ? '?' : ''}: ${type}`)} }` + }) + .toSorted() + // A function can have multiples definitions with differents args, but will always return the same type + .join(' | ')} + Returns: ${(() => { + // Case 1: `returns table`. + const tableArgs = fns[0].args.filter(({ mode }) => mode === 'table') + if (tableArgs.length > 0) { + const argsNameAndType = tableArgs.map(({ name, type_id }) => { + const type = types.find(({ id }) => id === type_id) + let tsType = 'unknown' + if (type) { + tsType = pgTypeToTsType(schema, type.name, { + types, + schemas, + tables, + views, + }) + } + return { name, type: tsType } + }) + + return `{ + ${argsNameAndType.map( + ({ name, type }) => `${JSON.stringify(name)}: ${type}` + )} + }` + } + + // Case 2: returns a relation's row type. + const relation = [...tables, ...views].find( + ({ id }) => id === fns[0].return_type_relation_id + ) + if (relation) { + return `{ + ${columnsByTableId[relation.id].map( + (column) => + `${JSON.stringify(column.name)}: ${pgTypeToTsType( + schema, + column.format, + { + types, + schemas, + tables, + views, + } + )} ${column.is_nullable ? '| null' : ''}` + )} + }` + } + + // Case 3: returns base/array/composite/enum type. + const type = types.find(({ id }) => id === fns[0].return_type_id) + if (type) { + return pgTypeToTsType(schema, type.name, { + types, + schemas, + tables, + views, + }) + } + + return 'unknown' + })()}${fns[0].is_set_returning_function ? '[]' : ''} + }` + ) + })()} + } + Enums: { + ${ + schemaEnums.length === 0 + ? '[_ in never]: never' + : schemaEnums.map( + (enum_) => + `${JSON.stringify(enum_.name)}: ${enum_.enums + .map((variant) => JSON.stringify(variant)) + .join('|')}` + ) + } + } + CompositeTypes: { + ${ + schemaCompositeTypes.length === 0 + ? '[_ in never]: never' + : schemaCompositeTypes.map( + ({ name, attributes }) => + `${JSON.stringify(name)}: { + ${attributes.map(({ name, type_id }) => { + const type = types.find(({ id }) => id === type_id) + let tsType = 'unknown' + if (type) { + tsType = `${pgTypeToTsType(schema, type.name, { + types, + schemas, + tables, + views, + })} | null` + } + return `${JSON.stringify(name)}: ${tsType}` + })} + }` + ) + } + } + }` + })} +} + +type DefaultSchema = Database[Extract] + +export type Tables< + DefaultSchemaTableNameOrOptions extends + | keyof (DefaultSchema["Tables"] & DefaultSchema["Views"]) + | { schema: keyof Database }, + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof Database + } + ? keyof (Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] & + Database[DefaultSchemaTableNameOrOptions["schema"]]["Views"]) + : never = never, +> = DefaultSchemaTableNameOrOptions extends { schema: keyof Database } + ? (Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] & + Database[DefaultSchemaTableNameOrOptions["schema"]]["Views"])[TableName] extends { + Row: infer R + } + ? R + : never + : DefaultSchemaTableNameOrOptions extends keyof (DefaultSchema["Tables"] & + DefaultSchema["Views"]) + ? (DefaultSchema["Tables"] & + DefaultSchema["Views"])[DefaultSchemaTableNameOrOptions] extends { + Row: infer R + } + ? R + : never + : never + +export type TablesInsert< + DefaultSchemaTableNameOrOptions extends + | keyof DefaultSchema["Tables"] + | { schema: keyof Database }, + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof Database + } + ? keyof Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] + : never = never, +> = DefaultSchemaTableNameOrOptions extends { schema: keyof Database } + ? Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"][TableName] extends { + Insert: infer I + } + ? I + : never + : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema["Tables"] + ? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends { + Insert: infer I + } + ? I + : never + : never + +export type TablesUpdate< + DefaultSchemaTableNameOrOptions extends + | keyof DefaultSchema["Tables"] + | { schema: keyof Database }, + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof Database + } + ? keyof Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] + : never = never, +> = DefaultSchemaTableNameOrOptions extends { schema: keyof Database } + ? Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"][TableName] extends { + Update: infer U + } + ? U + : never + : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema["Tables"] + ? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends { + Update: infer U + } + ? U + : never + : never + +export type Enums< + DefaultSchemaEnumNameOrOptions extends + | keyof DefaultSchema["Enums"] + | { schema: keyof Database }, + EnumName extends DefaultSchemaEnumNameOrOptions extends { + schema: keyof Database + } + ? keyof Database[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"] + : never = never, +> = DefaultSchemaEnumNameOrOptions extends { schema: keyof Database } + ? Database[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"][EnumName] + : DefaultSchemaEnumNameOrOptions extends keyof DefaultSchema["Enums"] + ? DefaultSchema["Enums"][DefaultSchemaEnumNameOrOptions] + : never + +export type CompositeTypes< + PublicCompositeTypeNameOrOptions extends + | keyof DefaultSchema["CompositeTypes"] + | { schema: keyof Database }, + CompositeTypeName extends PublicCompositeTypeNameOrOptions extends { + schema: keyof Database + } + ? keyof Database[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"] + : never = never, +> = PublicCompositeTypeNameOrOptions extends { schema: keyof Database } + ? Database[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"][CompositeTypeName] + : PublicCompositeTypeNameOrOptions extends keyof DefaultSchema["CompositeTypes"] + ? DefaultSchema["CompositeTypes"][PublicCompositeTypeNameOrOptions] + : never + +export const Constants = { + ${schemas + .sort(({ name: a }, { name: b }) => a.localeCompare(b)) + .map((schema) => { + const schemaEnums = types + .filter((type) => type.schema === schema.name && type.enums.length > 0) + .sort(({ name: a }, { name: b }) => a.localeCompare(b)) + return `${JSON.stringify(schema.name)}: { + Enums: { + ${schemaEnums.map( + (enum_) => + `${JSON.stringify(enum_.name)}: [${enum_.enums + .map((variant) => JSON.stringify(variant)) + .join(', ')}]` + )} + } + }` + })} +} as const +` + + output = await prettier.format(output, { + parser: 'typescript', + semi: false, + }) + return output +} + +// TODO: Make this more robust. Currently doesn't handle range types - returns them as unknown. +const pgTypeToTsType = ( + schema: PostgresSchema, + pgType: string, + { + types, + schemas, + tables, + views, + }: { + types: PostgresType[] + schemas: PostgresSchema[] + tables: PostgresTable[] + views: PostgresView[] + } +): string => { + if (pgType === 'bool') { + return 'boolean' + } else if (['int2', 'int4', 'int8', 'float4', 'float8', 'numeric'].includes(pgType)) { + return 'number' + } else if ( + [ + 'bytea', + 'bpchar', + 'varchar', + 'date', + 'text', + 'citext', + 'time', + 'timetz', + 'timestamp', + 'timestamptz', + 'uuid', + 'vector', + ].includes(pgType) + ) { + return 'string' + } else if (['json', 'jsonb'].includes(pgType)) { + return 'Json' + } else if (pgType === 'void') { + return 'undefined' + } else if (pgType === 'record') { + return 'Record' + } else if (pgType.startsWith('_')) { + return `(${pgTypeToTsType(schema, pgType.substring(1), { + types, + schemas, + tables, + views, + })})[]` + } else { + const enumTypes = types.filter((type) => type.name === pgType && type.enums.length > 0) + if (enumTypes.length > 0) { + const enumType = enumTypes.find((type) => type.schema === schema.name) || enumTypes[0] + if (schemas.some(({ name }) => name === enumType.schema)) { + return `Database[${JSON.stringify(enumType.schema)}]['Enums'][${JSON.stringify( + enumType.name + )}]` + } + return enumType.enums.map((variant) => JSON.stringify(variant)).join('|') + } + + const compositeTypes = types.filter( + (type) => type.name === pgType && type.attributes.length > 0 + ) + if (compositeTypes.length > 0) { + const compositeType = + compositeTypes.find((type) => type.schema === schema.name) || compositeTypes[0] + if (schemas.some(({ name }) => name === compositeType.schema)) { + return `Database[${JSON.stringify( + compositeType.schema + )}]['CompositeTypes'][${JSON.stringify(compositeType.name)}]` + } + return 'unknown' + } + + const tableRowTypes = tables.filter((table) => table.name === pgType) + if (tableRowTypes.length > 0) { + const tableRowType = + tableRowTypes.find((type) => type.schema === schema.name) || tableRowTypes[0] + if (schemas.some(({ name }) => name === tableRowType.schema)) { + return `Database[${JSON.stringify(tableRowType.schema)}]['Tables'][${JSON.stringify( + tableRowType.name + )}]['Row']` + } + return 'unknown' + } + + const viewRowTypes = views.filter((view) => view.name === pgType) + if (viewRowTypes.length > 0) { + const viewRowType = + viewRowTypes.find((type) => type.schema === schema.name) || viewRowTypes[0] + if (schemas.some(({ name }) => name === viewRowType.schema)) { + return `Database[${JSON.stringify(viewRowType.schema)}]['Views'][${JSON.stringify( + viewRowType.name + )}]['Row']` + } + return 'unknown' + } + + return 'unknown' + } +} diff --git a/src/server/utils.ts b/src/server/utils.ts index 92a3f6a6..ebb8ec90 100644 --- a/src/server/utils.ts +++ b/src/server/utils.ts @@ -1,11 +1,13 @@ -import { parse } from 'pg-connection-string' +import pgcs from 'pg-connection-string' import { FastifyRequest } from 'fastify' +import { DEFAULT_POOL_CONFIG } from './constants.js' +import { PoolConfig } from '../lib/types.js' export const extractRequestForLogging = (request: FastifyRequest) => { let pg: string = 'unknown' try { if (request.headers.pg) { - pg = parse(request.headers.pg as string).host || pg + pg = pgcs.parse(request.headers.pg as string).host || pg } } catch (e: any) { console.warn('failed to parse PG connstring for ' + request.url) @@ -21,12 +23,28 @@ export const extractRequestForLogging = (request: FastifyRequest) => { } } +export function createConnectionConfig(request: FastifyRequest): PoolConfig { + const connectionString = request.headers.pg as string + const config = { ...DEFAULT_POOL_CONFIG, connectionString } + + // Override application_name if custom one provided in header + if (request.headers['x-pg-application-name']) { + config.application_name = request.headers['x-pg-application-name'] as string + } + + return config +} + export function translateErrorToResponseCode( error: { message: string }, defaultResponseCode = 400 ): number { if (error.message === 'Connection terminated due to connection timeout') { return 504 + } else if (error.message === 'sorry, too many clients already') { + return 503 + } else if (error.message === 'Query read timeout') { + return 408 } return defaultResponseCode } diff --git a/test/db/00-init.sql b/test/db/00-init.sql index 4ea42022..00c6a472 100644 --- a/test/db/00-init.sql +++ b/test/db/00-init.sql @@ -3,6 +3,8 @@ -- Tables for testing CREATE TYPE public.user_status AS ENUM ('ACTIVE', 'INACTIVE'); +CREATE TYPE composite_type_with_array_attribute AS (my_text_array text[]); + CREATE TABLE public.users ( id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, name text, @@ -51,3 +53,131 @@ end; $$ language plpgsql; CREATE VIEW todos_view AS SELECT * FROM public.todos; +-- For testing typegen on view-to-view relationships +create view users_view as select * from public.users; + +create materialized view todos_matview as select * from public.todos; + +create function public.blurb(public.todos) returns text as +$$ +select substring($1.details, 1, 3); +$$ language sql stable; + +create function public.blurb_varchar(public.todos) returns character varying as +$$ +select substring($1.details, 1, 3); +$$ language sql stable; + +create function public.details_length(public.todos) returns integer as +$$ +select length($1.details); +$$ language sql stable; + +create function public.details_is_long(public.todos) returns boolean as +$$ +select $1.details_length > 20; +$$ language sql stable; + +create function public.details_words(public.todos) returns text[] as +$$ +select string_to_array($1.details, ' '); +$$ language sql stable; + +create extension postgres_fdw; +create server foreign_server foreign data wrapper postgres_fdw options (host 'localhost', port '5432', dbname 'postgres'); +create user mapping for postgres server foreign_server options (user 'postgres', password 'postgres'); +create foreign table foreign_table ( + id int8 not null, + name text, + status user_status +) server foreign_server options (schema_name 'public', table_name 'users'); + +create or replace function public.function_returning_row() +returns public.users +language sql +stable +as $$ + select * from public.users limit 1; +$$; + +create or replace function public.function_returning_set_of_rows() +returns setof public.users +language sql +stable +as $$ + select * from public.users; +$$; + +create or replace function public.function_returning_table() +returns table (id int, name text) +language sql +stable +as $$ + select id, name from public.users; +$$; + +create or replace function public.polymorphic_function(text) returns void language sql as ''; +create or replace function public.polymorphic_function(bool) returns void language sql as ''; + +create table user_details ( + user_id int8 references users(id) primary key, + details text +); + +create view a_view as select id from users; + +create table empty(); + +create table table_with_other_tables_row_type ( + col1 user_details, + col2 a_view +); + +create table table_with_primary_key_other_than_id ( + other_id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name text +); + +create type composite_type_with_record_attribute as ( + todo todos +); + +create view users_view_with_multiple_refs_to_users as +WITH initial_user AS ( + SELECT + u.id as initial_id, + u.name as initial_name + FROM users u + where u.id = 1 +), +second_user AS ( + SELECT + u.id as second_id, + u.name as second_name + FROM users u + where u.id = 2 +) +SELECT * from initial_user iu +cross join second_user su; + +CREATE OR REPLACE FUNCTION public.get_user_audit_setof_single_row(user_row users) +RETURNS SETOF users_audit +LANGUAGE SQL STABLE +ROWS 1 +AS $$ + SELECT * FROM public.users_audit WHERE user_id = user_row.id; +$$; + +CREATE OR REPLACE FUNCTION public.get_todos_setof_rows(user_row users) +RETURNS SETOF todos +LANGUAGE SQL STABLE +AS $$ + SELECT * FROM public.todos WHERE "user-id" = user_row.id; +$$; + +CREATE OR REPLACE FUNCTION public.get_todos_setof_rows(todo_row todos) +RETURNS SETOF todos +LANGUAGE SQL STABLE +AS $$ + SELECT * FROM public.todos WHERE "user-id" = todo_row."user-id"; +$$; diff --git a/test/db/Dockerfile b/test/db/Dockerfile new file mode 100644 index 00000000..fb81d611 --- /dev/null +++ b/test/db/Dockerfile @@ -0,0 +1,3 @@ +FROM supabase/postgres:14.1.0 + +COPY --chown=postgres:postgres --chmod=600 server.key server.crt /var/lib/postgresql/ diff --git a/test/db/docker-compose.yml b/test/db/docker-compose.yml index 0d7b5bee..d64c92b4 100755 --- a/test/db/docker-compose.yml +++ b/test/db/docker-compose.yml @@ -1,10 +1,16 @@ services: db: - image: supabase/postgres:14.1.0 + build: . ports: - 5432:5432 volumes: - - .:/docker-entrypoint-initdb.d - environment: + - .:/docker-entrypoint-initdb.d + environment: POSTGRES_PASSWORD: postgres - command: postgres -c config_file=/etc/postgresql/postgresql.conf + command: postgres -c config_file=/etc/postgresql/postgresql.conf -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 1s + timeout: 2s + retries: 10 + start_period: 2s diff --git a/test/db/server.crt b/test/db/server.crt new file mode 100644 index 00000000..26118694 --- /dev/null +++ b/test/db/server.crt @@ -0,0 +1,77 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 41:a3:0e:d5:2f:07:82:95:c1:cc:c8:62:02:04:eb:7b:25:dc:3e:6b + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN = localhost + Validity + Not Before: Aug 2 10:31:43 2023 GMT + Not After : Jul 30 10:31:43 2033 GMT + Subject: CN = localhost + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:d6:4a:ec:0d:40:a8:b1:cd:e8:e9:16:41:a9:6b: + ed:7f:c4:ee:4e:b6:4e:83:5a:7c:37:81:8c:fd:90: + 07:da:57:d3:1b:91:2f:77:6d:a1:b0:38:48:08:03: + 1f:77:91:6a:91:39:54:06:87:20:33:c2:d9:20:e4: + 06:15:f9:59:fb:0e:db:2e:a0:81:c0:6c:47:f6:bc: + 00:0f:07:9a:36:a8:4c:c3:62:97:51:31:53:53:51: + 2a:d6:ff:ca:e6:cf:b2:8e:d7:89:ae:2b:a4:15:ed: + 7c:35:8e:5b:26:84:b1:4d:13:7a:3e:32:a3:56:53: + c1:e8:98:f2:4a:03:56:53:2e:db:c7:96:7e:d2:df: + ea:e5:d7:c2:35:93:61:0d:af:0c:c0:2e:b4:b2:a2: + b1:5a:8b:38:fa:e6:1c:c7:1e:20:d8:0e:b2:97:f2: + 82:6b:4a:1f:27:8c:c1:e4:63:df:42:9a:e3:6c:46: + 74:46:fb:f5:0e:12:d4:b9:12:ce:dc:22:dd:f0:5c: + 6e:e3:31:4f:1a:fa:de:31:15:ec:2a:9b:6c:ea:67: + bf:67:f7:13:44:ba:01:4a:dd:76:32:a8:59:82:13: + 81:f2:48:6d:f4:5d:f0:70:a1:7b:f0:be:46:3e:65: + 36:ee:f3:2e:39:00:52:2a:00:f3:d3:83:c9:55:56: + dd:93 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 79:57:F3:18:B8:6B:FB:64:39:B0:E8:CC:24:18:ED:C0:C1:37:E2:0D + X509v3 Authority Key Identifier: + 79:57:F3:18:B8:6B:FB:64:39:B0:E8:CC:24:18:ED:C0:C1:37:E2:0D + X509v3 Basic Constraints: critical + CA:TRUE + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 2b:d1:37:75:b5:92:9a:c9:ed:45:a6:46:ac:97:93:b9:bf:c0: + f3:7f:47:c3:bd:fd:bd:6b:58:ad:49:79:9d:31:18:3c:b9:94: + 4b:aa:ca:49:c9:04:c4:71:1f:62:9b:ce:3f:5a:24:ec:82:68: + a7:74:45:dd:b1:02:8a:f0:f2:4f:7f:3d:28:94:b0:5b:47:51: + f3:12:a5:ce:1b:32:9f:f8:c6:6a:61:c6:99:4c:f6:99:9e:44: + e4:e9:01:0c:45:1c:a4:5f:f3:69:2e:3d:a7:5d:62:ab:fb:e4: + ea:d2:56:0f:56:df:00:5d:fa:9e:62:2a:77:00:cd:cd:b4:d8: + b6:47:4b:84:73:85:3e:eb:4c:3e:2b:67:46:84:b1:22:1a:04: + 47:02:ca:a0:74:a5:97:28:89:56:aa:c6:4a:ce:97:9b:14:14: + 96:d7:26:60:38:fd:ec:ae:7d:ea:47:68:16:1c:ee:47:19:10: + 69:6a:25:67:71:ac:0b:f0:4a:b0:b3:e6:9b:5f:89:e8:e7:64: + f7:92:37:0c:72:8c:d0:32:c5:10:79:c1:2e:22:05:65:50:db: + d8:0e:bf:b6:d9:f1:7b:88:82:0e:be:06:9b:8c:96:e2:53:03: + 1f:de:86:39:d8:7e:4b:48:bb:11:d9:5d:41:68:82:49:e4:2b: + 33:79:1b:78 +-----BEGIN CERTIFICATE----- +MIIDCTCCAfGgAwIBAgIUQaMO1S8HgpXBzMhiAgTreyXcPmswDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIzMDgwMjEwMzE0M1oXDTMzMDcz +MDEwMzE0M1owFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEA1krsDUCosc3o6RZBqWvtf8TuTrZOg1p8N4GM/ZAH2lfT +G5Evd22hsDhICAMfd5FqkTlUBocgM8LZIOQGFflZ+w7bLqCBwGxH9rwADweaNqhM +w2KXUTFTU1Eq1v/K5s+yjteJriukFe18NY5bJoSxTRN6PjKjVlPB6JjySgNWUy7b +x5Z+0t/q5dfCNZNhDa8MwC60sqKxWos4+uYcxx4g2A6yl/KCa0ofJ4zB5GPfQprj +bEZ0Rvv1DhLUuRLO3CLd8Fxu4zFPGvreMRXsKpts6me/Z/cTRLoBSt12MqhZghOB +8kht9F3wcKF78L5GPmU27vMuOQBSKgDz04PJVVbdkwIDAQABo1MwUTAdBgNVHQ4E +FgQUeVfzGLhr+2Q5sOjMJBjtwME34g0wHwYDVR0jBBgwFoAUeVfzGLhr+2Q5sOjM +JBjtwME34g0wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAK9E3 +dbWSmsntRaZGrJeTub/A839Hw739vWtYrUl5nTEYPLmUS6rKSckExHEfYpvOP1ok +7IJop3RF3bECivDyT389KJSwW0dR8xKlzhsyn/jGamHGmUz2mZ5E5OkBDEUcpF/z +aS49p11iq/vk6tJWD1bfAF36nmIqdwDNzbTYtkdLhHOFPutMPitnRoSxIhoERwLK +oHSllyiJVqrGSs6XmxQUltcmYDj97K596kdoFhzuRxkQaWolZ3GsC/BKsLPmm1+J +6Odk95I3DHKM0DLFEHnBLiIFZVDb2A6/ttnxe4iCDr4Gm4yW4lMDH96GOdh+S0i7 +EdldQWiCSeQrM3kbeA== +-----END CERTIFICATE----- diff --git a/test/db/server.key b/test/db/server.key new file mode 100644 index 00000000..451756ed --- /dev/null +++ b/test/db/server.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDWSuwNQKixzejp +FkGpa+1/xO5Otk6DWnw3gYz9kAfaV9MbkS93baGwOEgIAx93kWqROVQGhyAzwtkg +5AYV+Vn7DtsuoIHAbEf2vAAPB5o2qEzDYpdRMVNTUSrW/8rmz7KO14muK6QV7Xw1 +jlsmhLFNE3o+MqNWU8HomPJKA1ZTLtvHln7S3+rl18I1k2ENrwzALrSyorFaizj6 +5hzHHiDYDrKX8oJrSh8njMHkY99CmuNsRnRG+/UOEtS5Es7cIt3wXG7jMU8a+t4x +Fewqm2zqZ79n9xNEugFK3XYyqFmCE4HySG30XfBwoXvwvkY+ZTbu8y45AFIqAPPT +g8lVVt2TAgMBAAECggEAHXE9I3OpzzF3pGbEGMSqZJlTFgoi7sCE5pTBy/4jsL0g +/92fxEHngDBgvTETUWNFCApKCtI6phdJq8+IgoZi9YU3Wh2qwMcKetJJE8eQnvKF +XCb0nAQx6vWbnt9AKnGI7+qZ5mM6moSplyt68eeIpgqyC0+mdMWck8TygnbDlTlP +W+lfAZoCnrPDe6ptKTKtSy3AdGteAKk0pdaiUPHjtMdtOMwXCcHQkKopVIstfAib +mvg2/3djn5OnYBmhOINIAZvNSoVr/s9I/yZc8V3z2/lPoLDRmEjCgIGba4zkG0Sr +oaHdxJz8eTuSPwI+jcjto3gPkBdL2658l4JLxXYgQQKBgQD+VWv+jJsB01ijZsI9 +cV1aS6bqyb5sJEc1EFOZtkUYEr0RB6ww4FrRY7uryMPjXf+y47RvGsev0GvWkpRZ +ijzGmfeqHMm9y+hjVxJ64nNOvxzpuVWG0s3JOBDnVY/4RmnW1qghlAI0QkwU7EHl +O4ql3QS5PQEzudhNpQltDHmL4QKBgQDXsleHOzf32HCFR3EWAy+rosuiianGu3LI +2toAX0NxCSkNCPHksfcEryoyrgKLCSzNoBtQMQkvk9sgbQfRLPZi3Lcng+wzjBEv +4uR/a2xdOwnCMCYc9KMjnVukhf5WZ+hJBc49lCqJtc4Mhl89icgrXxUG8YwqUqNK +qb9YMCH38wKBgE3JOnpj7pSkWxu+tfGs1mxjbu2oPkE85zpnf+onQQKX2JN40UUx +mRUpd6CWirLjcOz5j5nbiu9Ow2yg8BZinSvwszqoC1utHaokW1aSI8oV0XX6ZRoT +JzU/nIvkM2AvyPcYN9vtNK9fB33utEiz6TfJXUR6T//N+0XkD/n2MsaBAoGBALDY +A3NYVhbaWcasQEdv7VGnc5WbkJrjbMTIyhur/ztZ61JIlyqNzp0EkHBkwqkDqLwe +HMaurX1YmDwJqHMTjh6YH4JCYxIQMLc2K2lcxcfac7HGkDkFSgwVI+HMCi8Fmijk +nadXJ1koufsC4Gsv3/HPTwoWWHkKr96zNbI0JGWJAoGAFFw+fjx4gI+VDayf4NMd +feIpDF6O2uB9uKbTyNJjYoj9Jh0NkSHccgVb+j5BvnxBmAJHrMEr6Cz3bnlKlK0a +1+Oqyq8MaYRLk6J/xMGSUcfa3uRC5svq0s8ebbl84Kt23IW9NU+YycVnMzysMLsH +xn4VooZdfd3oNm2lpYURz3I= +-----END PRIVATE KEY----- diff --git a/test/index.test.ts b/test/index.test.ts new file mode 100644 index 00000000..6ca2b87e --- /dev/null +++ b/test/index.test.ts @@ -0,0 +1,26 @@ +// TODO: Change lib tests to server tests. +// https://github.com/supabase/postgres-meta/issues/397#issuecomment-1285078489 +import './lib/columns' +import './lib/config' +import './lib/extensions' +import './lib/foreign-tables' +import './lib/functions' +import './lib/policies' +import './lib/publications' +import './lib/roles' +import './lib/schemas' +import './lib/secrets' +import './lib/tables' +import './lib/triggers' +import './lib/types' +import './lib/version' +import './lib/views' +import './server/column-privileges' +import './server/indexes' +import './server/materialized-views' +import './server/query' +import './server/ssl' +import './server/table-privileges' +import './server/typegen' +import './server/result-size-limit' +import './server/query-timeout' diff --git a/test/lib/columns.ts b/test/lib/columns.ts index 00477274..3fcac79f 100644 --- a/test/lib/columns.ts +++ b/test/lib/columns.ts @@ -1,3 +1,4 @@ +import { expect, test } from 'vitest' import { pgMeta } from './utils' test('list', async () => { @@ -8,11 +9,12 @@ test('list', async () => { table_id: expect.any(Number), }, ` - Object { + { + "check": null, "comment": null, "data_type": "bigint", "default_value": null, - "enums": Array [], + "enums": [], "format": "int8", "id": StringMatching /\\^\\\\d\\+\\\\\\.3\\$/, "identity_generation": null, @@ -31,6 +33,112 @@ test('list', async () => { ) }) +test('list from a single table', async () => { + const { data: testTable }: any = await pgMeta.tables.create({ name: 't' }) + await pgMeta.query('alter table t add c1 text, add c2 text') + + const res = await pgMeta.columns.list({ tableId: testTable!.id }) + expect(res).toMatchInlineSnapshot( + { + data: [ + { + id: expect.stringMatching(/^\d+\.\d+$/), + table_id: expect.any(Number), + }, + + { + id: expect.stringMatching(/^\d+\.\d+$/), + table_id: expect.any(Number), + }, + ], + }, + ` + { + "data": [ + { + "check": null, + "comment": null, + "data_type": "text", + "default_value": null, + "enums": [], + "format": "text", + "id": StringMatching /\\^\\\\d\\+\\\\\\.\\\\d\\+\\$/, + "identity_generation": null, + "is_generated": false, + "is_identity": false, + "is_nullable": true, + "is_unique": false, + "is_updatable": true, + "name": "c1", + "ordinal_position": 1, + "schema": "public", + "table": "t", + "table_id": Any, + }, + { + "check": null, + "comment": null, + "data_type": "text", + "default_value": null, + "enums": [], + "format": "text", + "id": StringMatching /\\^\\\\d\\+\\\\\\.\\\\d\\+\\$/, + "identity_generation": null, + "is_generated": false, + "is_identity": false, + "is_nullable": true, + "is_unique": false, + "is_updatable": true, + "name": "c2", + "ordinal_position": 2, + "schema": "public", + "table": "t", + "table_id": Any, + }, + ], + "error": null, + } + ` + ) + + await pgMeta.tables.remove(testTable!.id) +}) + +test('list columns with included schemas', async () => { + let res = await pgMeta.columns.list({ + includedSchemas: ['public'], + }) + + expect(res.data?.length).toBeGreaterThan(0) + + res.data?.forEach((column) => { + expect(column.schema).toBe('public') + }) +}) + +test('list columns with excluded schemas', async () => { + let res = await pgMeta.columns.list({ + excludedSchemas: ['public'], + }) + + res.data?.forEach((column) => { + expect(column.schema).not.toBe('public') + }) +}) + +test('list columns with excluded schemas and include System Schemas', async () => { + let res = await pgMeta.columns.list({ + excludedSchemas: ['public'], + includeSystemSchemas: true, + }) + + expect(res.data?.length).toBeGreaterThan(0) + + res.data?.forEach((column) => { + expect(column.schema).not.toBe('public') + }) +}) + test('retrieve, create, update, delete', async () => { const { data: testTable }: any = await pgMeta.tables.create({ name: 't' }) @@ -44,12 +152,13 @@ test('retrieve, create, update, delete', async () => { expect(res).toMatchInlineSnapshot( { data: { id: expect.stringMatching(/^\d+\.1$/), table_id: expect.any(Number) } }, ` - Object { - "data": Object { + { + "data": { + "check": null, "comment": "foo", "data_type": "smallint", "default_value": "'42'::smallint", - "enums": Array [], + "enums": [], "format": "int2", "id": StringMatching /\\^\\\\d\\+\\\\\\.1\\$/, "identity_generation": null, @@ -74,12 +183,13 @@ test('retrieve, create, update, delete', async () => { data: { id: expect.stringMatching(/^\d+\.1$/), table_id: expect.any(Number) }, }, ` - Object { - "data": Object { + { + "data": { + "check": null, "comment": "foo", "data_type": "smallint", "default_value": "'42'::smallint", - "enums": Array [], + "enums": [], "format": "int2", "id": StringMatching /\\^\\\\d\\+\\\\\\.1\\$/, "identity_generation": null, @@ -112,12 +222,13 @@ test('retrieve, create, update, delete', async () => { data: { id: expect.stringMatching(/^\d+\.1$/), table_id: expect.any(Number) }, }, ` - Object { - "data": Object { + { + "data": { + "check": null, "comment": "bar", "data_type": "integer", "default_value": null, - "enums": Array [], + "enums": [], "format": "int4", "id": StringMatching /\\^\\\\d\\+\\\\\\.1\\$/, "identity_generation": "ALWAYS", @@ -142,12 +253,13 @@ test('retrieve, create, update, delete', async () => { data: { id: expect.stringMatching(/^\d+\.1$/), table_id: expect.any(Number) }, }, ` - Object { - "data": Object { + { + "data": { + "check": null, "comment": "bar", "data_type": "integer", "default_value": null, - "enums": Array [], + "enums": [], "format": "int4", "id": StringMatching /\\^\\\\d\\+\\\\\\.1\\$/, "identity_generation": "ALWAYS", @@ -187,11 +299,12 @@ test('enum column with quoted name', async () => { table_id: expect.any(Number), }, ` - Object { + { + "check": null, "comment": null, "data_type": "USER-DEFINED", "default_value": null, - "enums": Array [ + "enums": [ "v", ], "format": "T", @@ -232,9 +345,9 @@ WHERE i.indrelid = '${testTable!.name}'::regclass AND i.indisprimary; `) expect(res).toMatchInlineSnapshot(` - Object { - "data": Array [ - Object { + { + "data": [ + { "attname": "c", }, ], @@ -264,9 +377,9 @@ WHERE i.indrelid = '${testTable!.name}'::regclass AND i.indisunique; `) expect(res).toMatchInlineSnapshot(` - Object { - "data": Array [ - Object { + { + "data": [ + { "attname": "c", }, ], @@ -293,12 +406,13 @@ test('array column', async () => { }, }, ` - Object { - "data": Object { + { + "data": { + "check": null, "comment": null, "data_type": "ARRAY", "default_value": null, - "enums": Array [], + "enums": [], "format": "_int2", "id": StringMatching /\\^\\\\d\\+\\\\\\.1\\$/, "identity_generation": null, @@ -339,12 +453,13 @@ test('column with default value', async () => { }, }, ` - Object { - "data": Object { + { + "data": { + "check": null, "comment": null, "data_type": "timestamp with time zone", "default_value": "now()", - "enums": Array [], + "enums": [], "format": "timestamptz", "id": StringMatching /\\^\\\\d\\+\\\\\\.1\\$/, "identity_generation": null, @@ -384,9 +499,9 @@ SELECT pg_get_constraintdef(( )); `) expect(res).toMatchInlineSnapshot(` - Object { - "data": Array [ - Object { + { + "data": [ + { "pg_get_constraintdef": null, }, ], @@ -416,12 +531,13 @@ test('update with name unchanged', async () => { }, }, ` - Object { - "data": Object { + { + "data": { + "check": null, "comment": null, "data_type": "smallint", "default_value": null, - "enums": Array [], + "enums": [], "format": "int2", "id": StringMatching /\\^\\\\d\\+\\\\\\.1\\$/, "identity_generation": null, @@ -463,12 +579,13 @@ test('update with array types', async () => { }, }, ` - Object { - "data": Object { + { + "data": { + "check": null, "comment": null, "data_type": "ARRAY", "default_value": null, - "enums": Array [], + "enums": [], "format": "_text", "id": StringMatching /\\^\\\\d\\+\\\\\\.1\\$/, "identity_generation": null, @@ -510,12 +627,13 @@ test('update with incompatible types', async () => { }, }, ` - Object { - "data": Object { + { + "data": { + "check": null, "comment": null, "data_type": "integer", "default_value": null, - "enums": Array [], + "enums": [], "format": "int4", "id": StringMatching /\\^\\\\d\\+\\\\\\.1\\$/, "identity_generation": null, @@ -556,12 +674,13 @@ test('update is_unique', async () => { }, }, ` - Object { - "data": Object { + { + "data": { + "check": null, "comment": null, "data_type": "text", "default_value": null, - "enums": Array [], + "enums": [], "format": "text", "id": StringMatching /\\^\\\\d\\+\\\\\\.1\\$/, "identity_generation": null, @@ -589,12 +708,13 @@ test('update is_unique', async () => { }, }, ` - Object { - "data": Object { + { + "data": { + "check": null, "comment": null, "data_type": "text", "default_value": null, - "enums": Array [], + "enums": [], "format": "text", "id": StringMatching /\\^\\\\d\\+\\\\\\.1\\$/, "identity_generation": null, @@ -637,12 +757,13 @@ test('alter column to type with uppercase', async () => { }, }, ` - Object { - "data": Object { + { + "data": { + "check": null, "comment": null, "data_type": "USER-DEFINED", "default_value": null, - "enums": Array [], + "enums": [], "format": "T", "id": StringMatching /\\^\\\\d\\+\\\\\\.1\\$/, "identity_generation": null, @@ -665,3 +786,234 @@ test('alter column to type with uppercase', async () => { await pgMeta.tables.remove(testTable!.id) await pgMeta.query('DROP TYPE "T"') }) + +test('enums are populated in enum array columns', async () => { + await pgMeta.query(`create type test_enum as enum ('a')`) + const { data: testTable } = await pgMeta.tables.create({ name: 't' }) + + let res = await pgMeta.columns.create({ + table_id: testTable!.id, + name: 'c', + type: '_test_enum', + }) + expect(res).toMatchInlineSnapshot( + { + data: { + id: expect.stringMatching(/^\d+\.1$/), + table_id: expect.any(Number), + }, + }, + ` + { + "data": { + "check": null, + "comment": null, + "data_type": "ARRAY", + "default_value": null, + "enums": [ + "a", + ], + "format": "_test_enum", + "id": StringMatching /\\^\\\\d\\+\\\\\\.1\\$/, + "identity_generation": null, + "is_generated": false, + "is_identity": false, + "is_nullable": true, + "is_unique": false, + "is_updatable": true, + "name": "c", + "ordinal_position": 1, + "schema": "public", + "table": "t", + "table_id": Any, + }, + "error": null, + } + ` + ) + + await pgMeta.tables.remove(testTable!.id) + await pgMeta.query(`drop type test_enum`) +}) + +test('drop with cascade', async () => { + await pgMeta.query(` +create table public.t ( + id int8 primary key, + t_id int8 generated always as (id) stored +); +`) + + let res = await pgMeta.columns.retrieve({ + schema: 'public', + table: 't', + name: 'id', + }) + res = await pgMeta.columns.remove(res.data!.id, { cascade: true }) + expect(res).toMatchInlineSnapshot( + { + data: { + id: expect.stringMatching(/^\d+\.1$/), + table_id: expect.any(Number), + }, + }, + ` + { + "data": { + "check": null, + "comment": null, + "data_type": "bigint", + "default_value": null, + "enums": [], + "format": "int8", + "id": StringMatching /\\^\\\\d\\+\\\\\\.1\\$/, + "identity_generation": null, + "is_generated": false, + "is_identity": false, + "is_nullable": false, + "is_unique": false, + "is_updatable": true, + "name": "id", + "ordinal_position": 1, + "schema": "public", + "table": "t", + "table_id": Any, + }, + "error": null, + } + ` + ) + + res = await pgMeta.columns.retrieve({ + schema: 'public', + table: 't', + name: 't_id', + }) + expect(res).toMatchInlineSnapshot(` + { + "data": null, + "error": { + "message": "Cannot find a column named t_id in table public.t", + }, + } + `) + + await pgMeta.query(`drop table public.t;`) +}) + +test('column with multiple checks', async () => { + await pgMeta.query(`create table t(c int8 check (c != 0) check (c != -1))`) + + const res = await pgMeta.columns.list() + const columns = res.data + ?.filter((c) => c.schema === 'public' && c.table === 't') + .map(({ id, table_id, ...c }) => c) + expect(columns).toMatchInlineSnapshot(` + [ + { + "check": "c <> 0", + "comment": null, + "data_type": "bigint", + "default_value": null, + "enums": [], + "format": "int8", + "identity_generation": null, + "is_generated": false, + "is_identity": false, + "is_nullable": true, + "is_unique": false, + "is_updatable": true, + "name": "c", + "ordinal_position": 1, + "schema": "public", + "table": "t", + }, + ] + `) + + await pgMeta.query(`drop table t`) +}) + +test('column with multiple unique constraints', async () => { + await pgMeta.query(`create table t(c int8 unique); alter table t add unique (c);`) + + const res = await pgMeta.columns.list() + const columns = res.data + ?.filter((c) => c.schema === 'public' && c.table === 't') + .map(({ id, table_id, ...c }) => c) + expect(columns).toMatchInlineSnapshot(` + [ + { + "check": null, + "comment": null, + "data_type": "bigint", + "default_value": null, + "enums": [], + "format": "int8", + "identity_generation": null, + "is_generated": false, + "is_identity": false, + "is_nullable": true, + "is_unique": true, + "is_updatable": true, + "name": "c", + "ordinal_position": 1, + "schema": "public", + "table": "t", + }, + ] + `) + + await pgMeta.query(`drop table t`) +}) + +test('dropping column checks', async () => { + await pgMeta.query(`create table public.t(c int8 check (c != 0))`) + + let res = await pgMeta.columns.retrieve({ + schema: 'public', + table: 't', + name: 'c', + }) + res = await pgMeta.columns.update(res.data!.id, { check: null }) + expect(res?.data?.check).toMatchInlineSnapshot(`null`) + + await pgMeta.query(`drop table t`) +}) + +test('column with fully-qualified type', async () => { + await pgMeta.query(`create table public.t(); create schema s; create type s.my_type as enum ();`) + + const table = await pgMeta.tables.retrieve({ + schema: 'public', + name: 't', + }) + const { data } = await pgMeta.columns.create({ + table_id: table.data!.id, + name: 'c', + type: 's.my_type', + }) + const { id, table_id, ...column } = data! + expect(column).toMatchInlineSnapshot(` + { + "check": null, + "comment": null, + "data_type": "USER-DEFINED", + "default_value": null, + "enums": [], + "format": "my_type", + "identity_generation": null, + "is_generated": false, + "is_identity": false, + "is_nullable": true, + "is_unique": false, + "is_updatable": true, + "name": "c", + "ordinal_position": 1, + "schema": "public", + "table": "t", + } + `) + + await pgMeta.query(`drop table public.t; drop schema s cascade;`) +}) diff --git a/test/lib/config.ts b/test/lib/config.ts index 2d0976dd..066139e5 100644 --- a/test/lib/config.ts +++ b/test/lib/config.ts @@ -1,28 +1,29 @@ +import { expect, test } from 'vitest' import { pgMeta } from './utils' test('list', async () => { const res = await pgMeta.config.list() expect(res.data?.find(({ name }) => name === 'autovacuum')).toMatchInlineSnapshot(` -Object { - "boot_val": "on", - "category": "Autovacuum", - "context": "sighup", - "enumvals": null, - "extra_desc": null, - "group": "Autovacuum", - "max_val": null, - "min_val": null, - "name": "autovacuum", - "pending_restart": false, - "reset_val": "on", - "setting": "on", - "short_desc": "Starts the autovacuum subprocess.", - "source": "default", - "sourcefile": null, - "sourceline": null, - "subgroup": "", - "unit": null, - "vartype": "bool", -} -`) + { + "boot_val": "on", + "category": "Autovacuum", + "context": "sighup", + "enumvals": null, + "extra_desc": null, + "group": "Autovacuum", + "max_val": null, + "min_val": null, + "name": "autovacuum", + "pending_restart": false, + "reset_val": "on", + "setting": "on", + "short_desc": "Starts the autovacuum subprocess.", + "source": "default", + "sourcefile": null, + "sourceline": null, + "subgroup": "", + "unit": null, + "vartype": "bool", + } + `) }) diff --git a/test/lib/extensions.ts b/test/lib/extensions.ts index dd4a5395..58615197 100644 --- a/test/lib/extensions.ts +++ b/test/lib/extensions.ts @@ -1,3 +1,4 @@ +import { expect, test } from 'vitest' import { pgMeta } from './utils' test('list', async () => { @@ -5,7 +6,7 @@ test('list', async () => { expect(res.data?.find(({ name }) => name === 'hstore')).toMatchInlineSnapshot( { default_version: expect.stringMatching(/^\d+.\d+$/) }, ` - Object { + { "comment": "data type for storing sets of (key, value) pairs", "default_version": StringMatching /\\^\\\\d\\+\\.\\\\d\\+\\$/, "installed_version": null, @@ -27,8 +28,8 @@ test('retrieve, create, update, delete', async () => { }, }, ` - Object { - "data": Object { + { + "data": { "comment": "data type for storing sets of (key, value) pairs", "default_version": StringMatching /\\^\\\\d\\+\\.\\\\d\\+\\$/, "installed_version": "1.4", @@ -47,8 +48,8 @@ test('retrieve, create, update, delete', async () => { }, }, ` - Object { - "data": Object { + { + "data": { "comment": "data type for storing sets of (key, value) pairs", "default_version": StringMatching /\\^\\\\d\\+\\.\\\\d\\+\\$/, "installed_version": "1.4", @@ -68,8 +69,8 @@ test('retrieve, create, update, delete', async () => { }, }, ` - Object { - "data": Object { + { + "data": { "comment": "data type for storing sets of (key, value) pairs", "default_version": StringMatching /\\^\\\\d\\+\\.\\\\d\\+\\$/, "installed_version": StringMatching /\\^\\\\d\\+\\.\\\\d\\+\\$/, @@ -89,8 +90,8 @@ test('retrieve, create, update, delete', async () => { }, }, ` - Object { - "data": Object { + { + "data": { "comment": "data type for storing sets of (key, value) pairs", "default_version": StringMatching /\\^\\\\d\\+\\.\\\\d\\+\\$/, "installed_version": StringMatching /\\^\\\\d\\+\\.\\\\d\\+\\$/, @@ -105,8 +106,8 @@ test('retrieve, create, update, delete', async () => { expect(res).toMatchInlineSnapshot( { data: { default_version: expect.stringMatching(/^\d+.\d+$/) } }, ` - Object { - "data": Object { + { + "data": { "comment": "data type for storing sets of (key, value) pairs", "default_version": StringMatching /\\^\\\\d\\+\\.\\\\d\\+\\$/, "installed_version": null, diff --git a/test/lib/foreign-tables.ts b/test/lib/foreign-tables.ts new file mode 100644 index 00000000..6be2360f --- /dev/null +++ b/test/lib/foreign-tables.ts @@ -0,0 +1,175 @@ +import { expect, test } from 'vitest' +import { pgMeta } from './utils' + +const cleanNondetFromResponse = (x: T) => { + const { data, ...rest } = x as any + + const cleanNondetFromData = ({ id, columns, ...rest }: any) => { + const cleaned = rest + if (columns) { + cleaned.columns = columns.map(({ id, table_id, ...rest }: any) => rest) + } + return cleaned + } + + return { + data: Array.isArray(data) ? data.map(cleanNondetFromData) : cleanNondetFromData(data), + ...rest, + } as T +} + +test('list', async () => { + const res = await pgMeta.foreignTables.list() + expect(cleanNondetFromResponse(res).data?.find(({ name }) => name === 'foreign_table')) + .toMatchInlineSnapshot(` + { + "columns": [ + { + "check": null, + "comment": null, + "data_type": "bigint", + "default_value": null, + "enums": [], + "format": "int8", + "identity_generation": null, + "is_generated": false, + "is_identity": false, + "is_nullable": false, + "is_unique": false, + "is_updatable": true, + "name": "id", + "ordinal_position": 1, + "schema": "public", + "table": "foreign_table", + }, + { + "check": null, + "comment": null, + "data_type": "text", + "default_value": null, + "enums": [], + "format": "text", + "identity_generation": null, + "is_generated": false, + "is_identity": false, + "is_nullable": true, + "is_unique": false, + "is_updatable": true, + "name": "name", + "ordinal_position": 2, + "schema": "public", + "table": "foreign_table", + }, + { + "check": null, + "comment": null, + "data_type": "USER-DEFINED", + "default_value": null, + "enums": [ + "ACTIVE", + "INACTIVE", + ], + "format": "user_status", + "identity_generation": null, + "is_generated": false, + "is_identity": false, + "is_nullable": true, + "is_unique": false, + "is_updatable": true, + "name": "status", + "ordinal_position": 3, + "schema": "public", + "table": "foreign_table", + }, + ], + "comment": null, + "name": "foreign_table", + "schema": "public", + } + `) +}) + +test('list without columns', async () => { + const res = await pgMeta.foreignTables.list({ includeColumns: false }) + expect(cleanNondetFromResponse(res).data?.find(({ name }) => name === 'foreign_table')) + .toMatchInlineSnapshot(` + { + "comment": null, + "name": "foreign_table", + "schema": "public", + } + `) +}) + +test('retrieve', async () => { + const res = await pgMeta.foreignTables.retrieve({ schema: 'public', name: 'foreign_table' }) + expect(cleanNondetFromResponse(res)).toMatchInlineSnapshot(` + { + "data": { + "columns": [ + { + "check": null, + "comment": null, + "data_type": "bigint", + "default_value": null, + "enums": [], + "format": "int8", + "identity_generation": null, + "is_generated": false, + "is_identity": false, + "is_nullable": false, + "is_unique": false, + "is_updatable": true, + "name": "id", + "ordinal_position": 1, + "schema": "public", + "table": "foreign_table", + }, + { + "check": null, + "comment": null, + "data_type": "text", + "default_value": null, + "enums": [], + "format": "text", + "identity_generation": null, + "is_generated": false, + "is_identity": false, + "is_nullable": true, + "is_unique": false, + "is_updatable": true, + "name": "name", + "ordinal_position": 2, + "schema": "public", + "table": "foreign_table", + }, + { + "check": null, + "comment": null, + "data_type": "USER-DEFINED", + "default_value": null, + "enums": [ + "ACTIVE", + "INACTIVE", + ], + "format": "user_status", + "identity_generation": null, + "is_generated": false, + "is_identity": false, + "is_nullable": true, + "is_unique": false, + "is_updatable": true, + "name": "status", + "ordinal_position": 3, + "schema": "public", + "table": "foreign_table", + }, + ], + "comment": null, + "name": "foreign_table", + "schema": "public", + }, + "error": null, + } + `) +}) diff --git a/test/lib/functions.ts b/test/lib/functions.ts index 04c8838a..05de3244 100644 --- a/test/lib/functions.ts +++ b/test/lib/functions.ts @@ -1,3 +1,4 @@ +import { expect, test } from 'vitest' import { pgMeta } from './utils' test('list', async () => { @@ -5,7 +6,21 @@ test('list', async () => { expect(res.data?.find(({ name }) => name === 'add')).toMatchInlineSnapshot( { id: expect.any(Number) }, ` - Object { + { + "args": [ + { + "has_default": false, + "mode": "in", + "name": "", + "type_id": 23, + }, + { + "has_default": false, + "mode": "in", + "name": "", + "type_id": 23, + }, + ], "argument_types": "integer, integer", "behavior": "IMMUTABLE", "complete_statement": "CREATE OR REPLACE FUNCTION public.add(integer, integer) @@ -18,9 +33,12 @@ test('list', async () => { "definition": "select $1 + $2;", "id": Any, "identity_argument_types": "integer, integer", + "is_set_returning_function": false, "language": "sql", "name": "add", - "return_type": "int4", + "return_type": "integer", + "return_type_id": 23, + "return_type_relation_id": null, "schema": "public", "security_definer": false, } @@ -28,6 +46,41 @@ test('list', async () => { ) }) +test('list functions with included schemas', async () => { + let res = await pgMeta.functions.list({ + includedSchemas: ['public'], + }) + + expect(res.data?.length).toBeGreaterThan(0) + + res.data?.forEach((func) => { + expect(func.schema).toBe('public') + }) +}) + +test('list functions with excluded schemas', async () => { + let res = await pgMeta.functions.list({ + excludedSchemas: ['public'], + }) + + res.data?.forEach((func) => { + expect(func.schema).not.toBe('public') + }) +}) + +test('list functions with excluded schemas and include System Schemas', async () => { + let res = await pgMeta.functions.list({ + excludedSchemas: ['public'], + includeSystemSchemas: true, + }) + + expect(res.data?.length).toBeGreaterThan(0) + + res.data?.forEach((func) => { + expect(func.schema).not.toBe('public') + }) +}) + test('retrieve, create, update, delete', async () => { const { data: { id: testSchemaId }, @@ -47,8 +100,22 @@ test('retrieve, create, update, delete', async () => { expect(res).toMatchInlineSnapshot( { data: { id: expect.any(Number) } }, ` - Object { - "data": Object { + { + "data": { + "args": [ + { + "has_default": false, + "mode": "in", + "name": "a", + "type_id": 21, + }, + { + "has_default": false, + "mode": "in", + "name": "b", + "type_id": 21, + }, + ], "argument_types": "a smallint, b smallint", "behavior": "STABLE", "complete_statement": "CREATE OR REPLACE FUNCTION public.test_func(a smallint, b smallint) @@ -59,16 +126,19 @@ test('retrieve, create, update, delete', async () => { SET role TO 'postgres' AS $function$select a + b$function$ ", - "config_params": Object { + "config_params": { "role": "postgres", "search_path": "hooks, auth", }, "definition": "select a + b", "id": Any, "identity_argument_types": "a smallint, b smallint", + "is_set_returning_function": false, "language": "sql", "name": "test_func", - "return_type": "int4", + "return_type": "integer", + "return_type_id": 23, + "return_type_relation_id": null, "schema": "public", "security_definer": true, }, @@ -80,8 +150,22 @@ test('retrieve, create, update, delete', async () => { expect(res).toMatchInlineSnapshot( { data: { id: expect.any(Number) } }, ` - Object { - "data": Object { + { + "data": { + "args": [ + { + "has_default": false, + "mode": "in", + "name": "a", + "type_id": 21, + }, + { + "has_default": false, + "mode": "in", + "name": "b", + "type_id": 21, + }, + ], "argument_types": "a smallint, b smallint", "behavior": "STABLE", "complete_statement": "CREATE OR REPLACE FUNCTION public.test_func(a smallint, b smallint) @@ -92,16 +176,19 @@ test('retrieve, create, update, delete', async () => { SET role TO 'postgres' AS $function$select a + b$function$ ", - "config_params": Object { + "config_params": { "role": "postgres", "search_path": "hooks, auth", }, "definition": "select a + b", "id": Any, "identity_argument_types": "a smallint, b smallint", + "is_set_returning_function": false, "language": "sql", "name": "test_func", - "return_type": "int4", + "return_type": "integer", + "return_type_id": 23, + "return_type_relation_id": null, "schema": "public", "security_definer": true, }, @@ -117,28 +204,45 @@ test('retrieve, create, update, delete', async () => { expect(res).toMatchInlineSnapshot( { data: { id: expect.any(Number) } }, ` - Object { - "data": Object { + { + "data": { + "args": [ + { + "has_default": false, + "mode": "in", + "name": "a", + "type_id": 21, + }, + { + "has_default": false, + "mode": "in", + "name": "b", + "type_id": 21, + }, + ], "argument_types": "a smallint, b smallint", "behavior": "STABLE", "complete_statement": "CREATE OR REPLACE FUNCTION test_schema.test_func_renamed(a smallint, b smallint) RETURNS integer LANGUAGE sql STABLE SECURITY DEFINER - SET search_path TO 'hooks', 'auth' SET role TO 'postgres' + SET search_path TO 'hooks', 'auth' AS $function$select b - a$function$ ", - "config_params": Object { + "config_params": { "role": "postgres", "search_path": "hooks, auth", }, "definition": "select b - a", "id": Any, "identity_argument_types": "a smallint, b smallint", + "is_set_returning_function": false, "language": "sql", "name": "test_func_renamed", - "return_type": "int4", + "return_type": "integer", + "return_type_id": 23, + "return_type_relation_id": null, "schema": "test_schema", "security_definer": true, }, @@ -150,28 +254,45 @@ test('retrieve, create, update, delete', async () => { expect(res).toMatchInlineSnapshot( { data: { id: expect.any(Number) } }, ` - Object { - "data": Object { + { + "data": { + "args": [ + { + "has_default": false, + "mode": "in", + "name": "a", + "type_id": 21, + }, + { + "has_default": false, + "mode": "in", + "name": "b", + "type_id": 21, + }, + ], "argument_types": "a smallint, b smallint", "behavior": "STABLE", "complete_statement": "CREATE OR REPLACE FUNCTION test_schema.test_func_renamed(a smallint, b smallint) RETURNS integer LANGUAGE sql STABLE SECURITY DEFINER - SET search_path TO 'hooks', 'auth' SET role TO 'postgres' + SET search_path TO 'hooks', 'auth' AS $function$select b - a$function$ ", - "config_params": Object { + "config_params": { "role": "postgres", "search_path": "hooks, auth", }, "definition": "select b - a", "id": Any, "identity_argument_types": "a smallint, b smallint", + "is_set_returning_function": false, "language": "sql", "name": "test_func_renamed", - "return_type": "int4", + "return_type": "integer", + "return_type_id": 23, + "return_type_relation_id": null, "schema": "test_schema", "security_definer": true, }, @@ -189,3 +310,47 @@ test('retrieve, create, update, delete', async () => { await pgMeta.schemas.remove(testSchemaId) }) + +test('retrieve set-returning function', async () => { + const res = await pgMeta.functions.retrieve({ + schema: 'public', + name: 'function_returning_set_of_rows', + args: [], + }) + expect(res.data).toMatchInlineSnapshot( + { + id: expect.any(Number), + return_type_id: expect.any(Number), + return_type_relation_id: expect.any(Number), + }, + ` + { + "args": [], + "argument_types": "", + "behavior": "STABLE", + "complete_statement": "CREATE OR REPLACE FUNCTION public.function_returning_set_of_rows() + RETURNS SETOF users + LANGUAGE sql + STABLE + AS $function$ + select * from public.users; + $function$ + ", + "config_params": null, + "definition": " + select * from public.users; + ", + "id": Any, + "identity_argument_types": "", + "is_set_returning_function": true, + "language": "sql", + "name": "function_returning_set_of_rows", + "return_type": "SETOF users", + "return_type_id": Any, + "return_type_relation_id": Any, + "schema": "public", + "security_definer": false, + } + ` + ) +}) diff --git a/test/lib/index.test.ts b/test/lib/index.test.ts deleted file mode 100644 index 24844229..00000000 --- a/test/lib/index.test.ts +++ /dev/null @@ -1,16 +0,0 @@ -// TODO: Strip nondeterministic values from snapshots. -// TODO: Test server. -import './query' -import './config' -import './version' -import './schemas' -import './types' -import './functions' -import './tables' -import './columns' -import './extensions' -import './roles' -import './policies' -import './publications' -import './triggers' -import './views' diff --git a/test/lib/policies.ts b/test/lib/policies.ts index b4e99a69..ef7eccbc 100644 --- a/test/lib/policies.ts +++ b/test/lib/policies.ts @@ -1,3 +1,4 @@ +import { expect, test } from 'vitest' import { pgMeta } from './utils' test('list', async () => { @@ -5,14 +6,14 @@ test('list', async () => { expect(res.data?.find(({ name }) => name === 'categories_update_policy')).toMatchInlineSnapshot( { id: expect.any(Number), table_id: expect.any(Number) }, ` - Object { + { "action": "PERMISSIVE", "check": null, "command": "UPDATE", "definition": "(current_setting('my.username'::text) = name)", "id": Any, "name": "categories_update_policy", - "roles": Array [ + "roles": [ "postgres", ], "schema": "public", @@ -23,6 +24,39 @@ test('list', async () => { ) }) +test('list policies with included schemas', async () => { + let res = await pgMeta.policies.list({ + includedSchemas: ['public'], + }) + + expect(res.data?.length).toBeGreaterThan(0) + + res.data?.forEach((policy) => { + expect(policy.schema).toBe('public') + }) +}) + +test('list policies with excluded schemas', async () => { + let res = await pgMeta.policies.list({ + excludedSchemas: ['public'], + }) + + res.data?.forEach((policy) => { + expect(policy.schema).not.toBe('public') + }) +}) + +test('list policies with excluded schemas and include System Schemas', async () => { + let res = await pgMeta.policies.list({ + excludedSchemas: ['public'], + includeSystemSchemas: true, + }) + + res.data?.forEach((policy) => { + expect(policy.schema).not.toBe('public') + }) +}) + test('retrieve, create, update, delete', async () => { let res = await pgMeta.policies.create({ name: 'test policy', @@ -38,15 +72,15 @@ test('retrieve, create, update, delete', async () => { }, }, ` - Object { - "data": Object { + { + "data": { "action": "RESTRICTIVE", "check": null, "command": "ALL", "definition": null, "id": Any, "name": "test policy", - "roles": Array [ + "roles": [ "public", ], "schema": "public", @@ -66,15 +100,15 @@ test('retrieve, create, update, delete', async () => { }, }, ` - Object { - "data": Object { + { + "data": { "action": "RESTRICTIVE", "check": null, "command": "ALL", "definition": null, "id": Any, "name": "test policy", - "roles": Array [ + "roles": [ "public", ], "schema": "public", @@ -89,6 +123,7 @@ test('retrieve, create, update, delete', async () => { name: 'policy updated', definition: "current_setting('my.username') IN (name)", check: "current_setting('my.username') IN (name)", + roles: ['postgres'], }) expect(res).toMatchInlineSnapshot( { @@ -98,16 +133,16 @@ test('retrieve, create, update, delete', async () => { }, }, ` - Object { - "data": Object { + { + "data": { "action": "RESTRICTIVE", "check": "(current_setting('my.username'::text) = name)", "command": "ALL", "definition": "(current_setting('my.username'::text) = name)", "id": Any, "name": "policy updated", - "roles": Array [ - "public", + "roles": [ + "postgres", ], "schema": "public", "table": "memes", @@ -126,16 +161,16 @@ test('retrieve, create, update, delete', async () => { }, }, ` - Object { - "data": Object { + { + "data": { "action": "RESTRICTIVE", "check": "(current_setting('my.username'::text) = name)", "command": "ALL", "definition": "(current_setting('my.username'::text) = name)", "id": Any, "name": "policy updated", - "roles": Array [ - "public", + "roles": [ + "postgres", ], "schema": "public", "table": "memes", diff --git a/test/lib/publications.ts b/test/lib/publications.ts index bd719ae1..1f1c973b 100644 --- a/test/lib/publications.ts +++ b/test/lib/publications.ts @@ -1,3 +1,4 @@ +import { expect, test } from 'vitest' import { pgMeta } from './utils' const cleanNondet = (x: any) => { @@ -27,8 +28,8 @@ test('retrieve, create, update, delete', async () => { expect(cleanNondet(res)).toMatchInlineSnapshot( { data: { id: expect.any(Number) } }, ` - Object { - "data": Object { + { + "data": { "id": Any, "name": "a", "owner": "postgres", @@ -36,8 +37,8 @@ test('retrieve, create, update, delete', async () => { "publish_insert": true, "publish_truncate": false, "publish_update": true, - "tables": Array [ - Object { + "tables": [ + { "name": "users", "schema": "public", }, @@ -51,8 +52,8 @@ test('retrieve, create, update, delete', async () => { expect(cleanNondet(res)).toMatchInlineSnapshot( { data: { id: expect.any(Number) } }, ` - Object { - "data": Object { + { + "data": { "id": Any, "name": "a", "owner": "postgres", @@ -60,8 +61,8 @@ test('retrieve, create, update, delete', async () => { "publish_insert": true, "publish_truncate": false, "publish_update": true, - "tables": Array [ - Object { + "tables": [ + { "name": "users", "schema": "public", }, @@ -79,8 +80,8 @@ test('retrieve, create, update, delete', async () => { expect(cleanNondet(res)).toMatchInlineSnapshot( { data: { id: expect.any(Number) } }, ` - Object { - "data": Object { + { + "data": { "id": Any, "name": "b", "owner": "postgres", @@ -88,7 +89,7 @@ test('retrieve, create, update, delete', async () => { "publish_insert": false, "publish_truncate": false, "publish_update": true, - "tables": Array [], + "tables": [], }, "error": null, } @@ -98,8 +99,8 @@ test('retrieve, create, update, delete', async () => { expect(cleanNondet(res)).toMatchInlineSnapshot( { data: { id: expect.any(Number) } }, ` - Object { - "data": Object { + { + "data": { "id": Any, "name": "b", "owner": "postgres", @@ -107,7 +108,7 @@ test('retrieve, create, update, delete', async () => { "publish_insert": false, "publish_truncate": false, "publish_update": true, - "tables": Array [], + "tables": [], }, "error": null, } @@ -134,8 +135,8 @@ test('tables with uppercase', async () => { expect(cleanNondet(res)).toMatchInlineSnapshot( { data: { id: expect.any(Number) } }, ` - Object { - "data": Object { + { + "data": { "id": Any, "name": "pub", "owner": "postgres", @@ -143,8 +144,8 @@ test('tables with uppercase', async () => { "publish_insert": false, "publish_truncate": false, "publish_update": false, - "tables": Array [ - Object { + "tables": [ + { "name": "T", "schema": "public", }, @@ -160,8 +161,8 @@ test('tables with uppercase', async () => { expect(cleanNondet(res)).toMatchInlineSnapshot( { data: { id: expect.any(Number) } }, ` - Object { - "data": Object { + { + "data": { "id": Any, "name": "pub", "owner": "postgres", @@ -169,8 +170,8 @@ test('tables with uppercase', async () => { "publish_insert": false, "publish_truncate": false, "publish_update": false, - "tables": Array [ - Object { + "tables": [ + { "name": "T", "schema": "public", }, @@ -196,8 +197,8 @@ test('FOR ALL TABLES', async () => { expect(cleanNondet(res)).toMatchInlineSnapshot( { data: { id: expect.any(Number) } }, ` - Object { - "data": Object { + { + "data": { "id": Any, "name": "for_all", "owner": "postgres", @@ -213,3 +214,57 @@ test('FOR ALL TABLES', async () => { ) await pgMeta.publications.remove(res.data!.id) }) + +test('update no tables -> all tables', async () => { + const { data } = await pgMeta.publications.create({ + name: 'pub', + tables: [], + }) + const res = await pgMeta.publications.update(data!.id, { tables: null }) + expect(cleanNondet(res)).toMatchInlineSnapshot( + { data: { id: expect.any(Number) } }, + ` + { + "data": { + "id": Any, + "name": "pub", + "owner": "postgres", + "publish_delete": false, + "publish_insert": false, + "publish_truncate": false, + "publish_update": false, + "tables": null, + }, + "error": null, + } + ` + ) + await pgMeta.publications.remove(res.data!.id) +}) + +test('update all tables -> no tables', async () => { + const { data } = await pgMeta.publications.create({ + name: 'pub', + tables: null, + }) + const res = await pgMeta.publications.update(data!.id, { tables: [] }) + expect(cleanNondet(res)).toMatchInlineSnapshot( + { data: { id: expect.any(Number) } }, + ` + { + "data": { + "id": Any, + "name": "pub", + "owner": "postgres", + "publish_delete": false, + "publish_insert": false, + "publish_truncate": false, + "publish_update": false, + "tables": [], + }, + "error": null, + } + ` + ) + await pgMeta.publications.remove(res.data!.id) +}) diff --git a/test/lib/query.ts b/test/lib/query.ts deleted file mode 100644 index 7715c376..00000000 --- a/test/lib/query.ts +++ /dev/null @@ -1,490 +0,0 @@ -import { pgMeta } from './utils' - -test('query', async () => { - const res = await pgMeta.query('SELECT * FROM users') - expect(res).toMatchInlineSnapshot(` - Object { - "data": Array [ - Object { - "id": 1, - "name": "Joe Bloggs", - "status": "ACTIVE", - }, - Object { - "id": 2, - "name": "Jane Doe", - "status": "ACTIVE", - }, - ], - "error": null, - } - `) -}) - -test('error', async () => { - const res = await pgMeta.query('DROP TABLE missing_table') - expect(res).toMatchInlineSnapshot(` - Object { - "data": null, - "error": Object { - "message": "table \\"missing_table\\" does not exist", - }, - } - `) -}) - -test('parser select statements', async () => { - const res = pgMeta.parse('SELECT id, name FROM users where user_id = 1234') - expect(res).toMatchInlineSnapshot(` - Object { - "data": Array [ - Object { - "RawStmt": Object { - "stmt": Object { - "SelectStmt": Object { - "fromClause": Array [ - Object { - "RangeVar": Object { - "inh": true, - "location": 21, - "relname": "users", - "relpersistence": "p", - }, - }, - ], - "limitOption": "LIMIT_OPTION_DEFAULT", - "op": "SETOP_NONE", - "targetList": Array [ - Object { - "ResTarget": Object { - "location": 7, - "val": Object { - "ColumnRef": Object { - "fields": Array [ - Object { - "String": Object { - "str": "id", - }, - }, - ], - "location": 7, - }, - }, - }, - }, - Object { - "ResTarget": Object { - "location": 11, - "val": Object { - "ColumnRef": Object { - "fields": Array [ - Object { - "String": Object { - "str": "name", - }, - }, - ], - "location": 11, - }, - }, - }, - }, - ], - "whereClause": Object { - "A_Expr": Object { - "kind": "AEXPR_OP", - "lexpr": Object { - "ColumnRef": Object { - "fields": Array [ - Object { - "String": Object { - "str": "user_id", - }, - }, - ], - "location": 33, - }, - }, - "location": 41, - "name": Array [ - Object { - "String": Object { - "str": "=", - }, - }, - ], - "rexpr": Object { - "A_Const": Object { - "location": 43, - "val": Object { - "Integer": Object { - "ival": 1234, - }, - }, - }, - }, - }, - }, - }, - }, - "stmt_len": undefined, - }, - }, - ], - "error": null, - } - `) -}) - -test('parser comments', async () => { - const res = pgMeta.parse(` --- test comments -`) - expect(res).toMatchInlineSnapshot(` - Object { - "data": Array [], - "error": null, - } - `) -}) - -test('parser create schema', async () => { - const res = pgMeta.parse(` -create schema if not exists test_schema; -`) - expect(res).toMatchInlineSnapshot(` - Object { - "data": Array [ - Object { - "RawStmt": Object { - "stmt": Object { - "CreateSchemaStmt": Object { - "if_not_exists": true, - "schemaname": "test_schema", - }, - }, - "stmt_len": 40, - }, - }, - ], - "error": null, - } - `) -}) - -test('parser create statements', async () => { - const query = ` -CREATE TABLE table_name ( - id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, - inserted_at timestamp with time zone DEFAULT timezone('utc'::text, now()) NOT NULL, - updated_at timestamp with time zone DEFAULT timezone('utc'::text, now()) NOT NULL, - data jsonb, - name text -); -` - const res = pgMeta.parse(query) - expect(res).toMatchInlineSnapshot(` - Object { - "data": Array [ - Object { - "RawStmt": Object { - "stmt": Object { - "CreateStmt": Object { - "oncommit": "ONCOMMIT_NOOP", - "relation": Object { - "inh": true, - "location": 14, - "relname": "table_name", - "relpersistence": "p", - }, - "tableElts": Array [ - Object { - "ColumnDef": Object { - "colname": "id", - "constraints": Array [ - Object { - "Constraint": Object { - "contype": "CONSTR_IDENTITY", - "generated_when": "d", - "location": 39, - }, - }, - Object { - "Constraint": Object { - "contype": "CONSTR_PRIMARY", - "location": 72, - }, - }, - ], - "is_local": true, - "location": 29, - "typeName": Object { - "location": 32, - "names": Array [ - Object { - "String": Object { - "str": "pg_catalog", - }, - }, - Object { - "String": Object { - "str": "int8", - }, - }, - ], - "typemod": -1, - }, - }, - }, - Object { - "ColumnDef": Object { - "colname": "inserted_at", - "constraints": Array [ - Object { - "Constraint": Object { - "contype": "CONSTR_DEFAULT", - "location": 124, - "raw_expr": Object { - "FuncCall": Object { - "args": Array [ - Object { - "TypeCast": Object { - "arg": Object { - "A_Const": Object { - "location": 141, - "val": Object { - "String": Object { - "str": "utc", - }, - }, - }, - }, - "location": 146, - "typeName": Object { - "location": 148, - "names": Array [ - Object { - "String": Object { - "str": "text", - }, - }, - ], - "typemod": -1, - }, - }, - }, - Object { - "FuncCall": Object { - "funcname": Array [ - Object { - "String": Object { - "str": "now", - }, - }, - ], - "location": 154, - }, - }, - ], - "funcname": Array [ - Object { - "String": Object { - "str": "timezone", - }, - }, - ], - "location": 132, - }, - }, - }, - }, - Object { - "Constraint": Object { - "contype": "CONSTR_NOTNULL", - "location": 161, - }, - }, - ], - "is_local": true, - "location": 87, - "typeName": Object { - "location": 99, - "names": Array [ - Object { - "String": Object { - "str": "pg_catalog", - }, - }, - Object { - "String": Object { - "str": "timestamptz", - }, - }, - ], - "typemod": -1, - }, - }, - }, - Object { - "ColumnDef": Object { - "colname": "updated_at", - "constraints": Array [ - Object { - "Constraint": Object { - "contype": "CONSTR_DEFAULT", - "location": 209, - "raw_expr": Object { - "FuncCall": Object { - "args": Array [ - Object { - "TypeCast": Object { - "arg": Object { - "A_Const": Object { - "location": 226, - "val": Object { - "String": Object { - "str": "utc", - }, - }, - }, - }, - "location": 231, - "typeName": Object { - "location": 233, - "names": Array [ - Object { - "String": Object { - "str": "text", - }, - }, - ], - "typemod": -1, - }, - }, - }, - Object { - "FuncCall": Object { - "funcname": Array [ - Object { - "String": Object { - "str": "now", - }, - }, - ], - "location": 239, - }, - }, - ], - "funcname": Array [ - Object { - "String": Object { - "str": "timezone", - }, - }, - ], - "location": 217, - }, - }, - }, - }, - Object { - "Constraint": Object { - "contype": "CONSTR_NOTNULL", - "location": 246, - }, - }, - ], - "is_local": true, - "location": 173, - "typeName": Object { - "location": 184, - "names": Array [ - Object { - "String": Object { - "str": "pg_catalog", - }, - }, - Object { - "String": Object { - "str": "timestamptz", - }, - }, - ], - "typemod": -1, - }, - }, - }, - Object { - "ColumnDef": Object { - "colname": "data", - "is_local": true, - "location": 258, - "typeName": Object { - "location": 263, - "names": Array [ - Object { - "String": Object { - "str": "jsonb", - }, - }, - ], - "typemod": -1, - }, - }, - }, - Object { - "ColumnDef": Object { - "colname": "name", - "is_local": true, - "location": 272, - "typeName": Object { - "location": 277, - "names": Array [ - Object { - "String": Object { - "str": "text", - }, - }, - ], - "typemod": -1, - }, - }, - }, - ], - }, - }, - "stmt_len": 283, - }, - }, - ], - "error": null, - } - `) - - const deparse = pgMeta.deparse(res.data!) - expect(deparse.data).toMatchInlineSnapshot(` -"CREATE TABLE table_name ( - id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, - inserted_at pg_catalog.timestamptz DEFAULT ( timezone('utc'::text, now()) ) NOT NULL, - updated_at pg_catalog.timestamptz DEFAULT ( timezone('utc'::text, now()) ) NOT NULL, - data jsonb, - name text -);" -`) -}) - -test('formatter', async () => { - const res = pgMeta.format('SELECT id, name FROM users where user_id = 1234') - expect(res).toMatchInlineSnapshot(` - Object { - "data": "SELECT - id, - name - FROM - users - where - user_id = 1234", - "error": null, - } - `) -}) diff --git a/test/lib/roles.ts b/test/lib/roles.ts index c7a57de1..516a0871 100644 --- a/test/lib/roles.ts +++ b/test/lib/roles.ts @@ -1,17 +1,15 @@ +import { expect, test } from 'vitest' import { pgMeta } from './utils' test('list', async () => { const res = await pgMeta.roles.list() - const { grants, ...rest }: any = res.data?.find(({ name }) => name === 'postgres') + let role = res.data?.find(({ name }) => name === 'postgres') - expect({ - grants: grants.map(({ table_id, ...rest }: any) => rest), - ...rest, - }).toMatchInlineSnapshot( + expect(role).toMatchInlineSnapshot( { active_connections: expect.any(Number), id: expect.any(Number) }, ` - Object { + { "active_connections": Any, "can_bypass_rls": true, "can_create_db": true, @@ -19,386 +17,6 @@ test('list', async () => { "can_login": true, "config": null, "connection_limit": 100, - "grants": Array [ - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "INSERT", - "schema": "public", - "table_name": "users", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "SELECT", - "schema": "public", - "table_name": "users", - "with_hierarchy": true, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "UPDATE", - "schema": "public", - "table_name": "users", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "DELETE", - "schema": "public", - "table_name": "users", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "TRUNCATE", - "schema": "public", - "table_name": "users", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "REFERENCES", - "schema": "public", - "table_name": "users", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "TRIGGER", - "schema": "public", - "table_name": "users", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "INSERT", - "schema": "public", - "table_name": "todos", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "SELECT", - "schema": "public", - "table_name": "todos", - "with_hierarchy": true, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "UPDATE", - "schema": "public", - "table_name": "todos", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "DELETE", - "schema": "public", - "table_name": "todos", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "TRUNCATE", - "schema": "public", - "table_name": "todos", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "REFERENCES", - "schema": "public", - "table_name": "todos", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "TRIGGER", - "schema": "public", - "table_name": "todos", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "INSERT", - "schema": "public", - "table_name": "users_audit", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "SELECT", - "schema": "public", - "table_name": "users_audit", - "with_hierarchy": true, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "UPDATE", - "schema": "public", - "table_name": "users_audit", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "DELETE", - "schema": "public", - "table_name": "users_audit", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "TRUNCATE", - "schema": "public", - "table_name": "users_audit", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "REFERENCES", - "schema": "public", - "table_name": "users_audit", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "TRIGGER", - "schema": "public", - "table_name": "users_audit", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "INSERT", - "schema": "public", - "table_name": "todos_view", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "SELECT", - "schema": "public", - "table_name": "todos_view", - "with_hierarchy": true, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "UPDATE", - "schema": "public", - "table_name": "todos_view", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "DELETE", - "schema": "public", - "table_name": "todos_view", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "TRUNCATE", - "schema": "public", - "table_name": "todos_view", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "REFERENCES", - "schema": "public", - "table_name": "todos_view", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "TRIGGER", - "schema": "public", - "table_name": "todos_view", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "INSERT", - "schema": "public", - "table_name": "category", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "SELECT", - "schema": "public", - "table_name": "category", - "with_hierarchy": true, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "UPDATE", - "schema": "public", - "table_name": "category", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "DELETE", - "schema": "public", - "table_name": "category", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "TRUNCATE", - "schema": "public", - "table_name": "category", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "REFERENCES", - "schema": "public", - "table_name": "category", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "TRIGGER", - "schema": "public", - "table_name": "category", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "INSERT", - "schema": "public", - "table_name": "memes", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "SELECT", - "schema": "public", - "table_name": "memes", - "with_hierarchy": true, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "UPDATE", - "schema": "public", - "table_name": "memes", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "DELETE", - "schema": "public", - "table_name": "memes", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "TRUNCATE", - "schema": "public", - "table_name": "memes", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "REFERENCES", - "schema": "public", - "table_name": "memes", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "TRIGGER", - "schema": "public", - "table_name": "memes", - "with_hierarchy": false, - }, - ], "id": Any, "inherit_role": true, "is_replication_role": true, @@ -409,6 +27,43 @@ test('list', async () => { } ` ) + + // pg_monitor is a predefined role. `includeDefaultRoles` defaults to false, + // so it shouldn't be included in the result. + role = res.data?.find(({ name }) => name === 'pg_monitor') + + expect(role).toMatchInlineSnapshot(`undefined`) +}) + +test('list w/ default roles', async () => { + const res = await pgMeta.roles.list({ includeDefaultRoles: true }) + + const role = res.data?.find(({ name }) => name === 'pg_monitor') + + expect(role).toMatchInlineSnapshot( + { + active_connections: expect.any(Number), + id: expect.any(Number), + }, + ` + { + "active_connections": Any, + "can_bypass_rls": false, + "can_create_db": false, + "can_create_role": false, + "can_login": false, + "config": null, + "connection_limit": 100, + "id": Any, + "inherit_role": true, + "is_replication_role": false, + "is_superuser": false, + "name": "pg_monitor", + "password": "********", + "valid_until": null, + } + ` + ) }) test('retrieve, create, update, delete', async () => { @@ -423,18 +78,21 @@ test('retrieve, create, update, delete', async () => { can_bypass_rls: true, connection_limit: 100, valid_until: '2020-01-01T00:00:00.000Z', + config: { search_path: 'extension, public' }, }) expect(res).toMatchInlineSnapshot( { data: { id: expect.any(Number) } }, ` - Object { - "data": Object { + { + "data": { "active_connections": 0, "can_bypass_rls": true, "can_create_db": true, "can_create_role": true, "can_login": true, - "config": null, + "config": { + "search_path": "extension, public", + }, "connection_limit": 100, "id": Any, "inherit_role": false, @@ -452,14 +110,16 @@ test('retrieve, create, update, delete', async () => { expect(res).toMatchInlineSnapshot( { data: { id: expect.any(Number) } }, ` - Object { - "data": Object { + { + "data": { "active_connections": 0, "can_bypass_rls": true, "can_create_db": true, "can_create_role": true, "can_login": true, - "config": null, + "config": { + "search_path": "extension, public", + }, "connection_limit": 100, "id": Any, "inherit_role": false, @@ -488,18 +148,68 @@ test('retrieve, create, update, delete', async () => { can_bypass_rls: true, connection_limit: 100, valid_until: '2020-01-01T00:00:00.000Z', + config: [ + { + op: 'replace', + path: 'search_path', + value: 'public', + }, + { + op: 'add', + path: 'log_statement', + value: 'all', + }, + ], }) expect(res).toMatchInlineSnapshot( { data: { id: expect.any(Number) } }, ` - Object { - "data": Object { + { + "data": { "active_connections": 0, "can_bypass_rls": true, "can_create_db": true, "can_create_role": true, "can_login": true, - "config": null, + "config": { + "log_statement": "all", + "search_path": "public", + }, + "connection_limit": 100, + "id": Any, + "inherit_role": false, + "is_replication_role": true, + "is_superuser": true, + "name": "rr", + "password": "********", + "valid_until": "2020-01-01 00:00:00+00", + }, + "error": null, + } + ` + ) + // Test remove config + res = await pgMeta.roles.update(res.data!.id, { + config: [ + { + op: 'remove', + path: 'log_statement', + }, + ], + }) + expect(res).toMatchInlineSnapshot( + { data: { id: expect.any(Number) } }, + ` + { + "data": { + "active_connections": 0, + "can_bypass_rls": true, + "can_create_db": true, + "can_create_role": true, + "can_login": true, + "config": { + "search_path": "public", + }, "connection_limit": 100, "id": Any, "inherit_role": false, @@ -517,14 +227,16 @@ test('retrieve, create, update, delete', async () => { expect(res).toMatchInlineSnapshot( { data: { id: expect.any(Number) } }, ` - Object { - "data": Object { + { + "data": { "active_connections": 0, "can_bypass_rls": true, "can_create_db": true, "can_create_role": true, "can_login": true, - "config": null, + "config": { + "search_path": "public", + }, "connection_limit": 100, "id": Any, "inherit_role": false, diff --git a/test/lib/schemas.ts b/test/lib/schemas.ts index 9856166a..b9fb4a77 100644 --- a/test/lib/schemas.ts +++ b/test/lib/schemas.ts @@ -1,3 +1,4 @@ +import { expect, test } from 'vitest' import { pgMeta } from './utils' test('list with system schemas', async () => { @@ -5,7 +6,7 @@ test('list with system schemas', async () => { expect(res.data?.find(({ name }) => name === 'pg_catalog')).toMatchInlineSnapshot( { id: expect.any(Number) }, ` - Object { + { "id": Any, "name": "pg_catalog", "owner": "postgres", @@ -20,7 +21,7 @@ test('list without system schemas', async () => { expect(res.data?.find(({ name }) => name === 'public')).toMatchInlineSnapshot( { id: expect.any(Number) }, ` - Object { + { "id": Any, "name": "public", "owner": "postgres", @@ -34,8 +35,8 @@ test('retrieve, create, update, delete', async () => { expect(res).toMatchInlineSnapshot( { data: { id: expect.any(Number) } }, ` - Object { - "data": Object { + { + "data": { "id": Any, "name": "s", "owner": "postgres", @@ -48,8 +49,8 @@ test('retrieve, create, update, delete', async () => { expect(res).toMatchInlineSnapshot( { data: { id: expect.any(Number) } }, ` - Object { - "data": Object { + { + "data": { "id": Any, "name": "s", "owner": "postgres", @@ -62,8 +63,8 @@ test('retrieve, create, update, delete', async () => { expect(res).toMatchInlineSnapshot( { data: { id: expect.any(Number) } }, ` - Object { - "data": Object { + { + "data": { "id": Any, "name": "ss", "owner": "postgres", @@ -76,8 +77,8 @@ test('retrieve, create, update, delete', async () => { expect(res).toMatchInlineSnapshot( { data: { id: expect.any(Number) } }, ` - Object { - "data": Object { + { + "data": { "id": Any, "name": "ss", "owner": "postgres", diff --git a/test/lib/secrets.ts b/test/lib/secrets.ts new file mode 100644 index 00000000..d71c8afc --- /dev/null +++ b/test/lib/secrets.ts @@ -0,0 +1,59 @@ +import { readFile } from 'node:fs/promises' +import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest' +import { getSecret } from '../../src/lib/secrets' + +vi.mock('node:fs/promises', async (): Promise => { + const originalModule = + await vi.importActual('node:fs/promises') + const readFile = vi.fn() + return { ...originalModule, readFile } +}) + +describe('getSecret', () => { + const value = 'dummy' + + beforeEach(() => { + // Clears env var + vi.resetModules() + }) + + afterEach(() => { + delete process.env.SECRET + delete process.env.SECRET_FILE + }) + + test('loads from env', async () => { + process.env.SECRET = value + const res = await getSecret('SECRET') + expect(res).toBe(value) + }) + + test('loads from file', async () => { + process.env.SECRET_FILE = '/run/secrets/db_password' + vi.mocked(readFile).mockResolvedValueOnce(value) + const res = await getSecret('SECRET') + expect(res).toBe(value) + }) + + test('defaults to empty string', async () => { + expect(await getSecret('')).toBe('') + expect(await getSecret('SECRET')).toBe('') + }) + + test('default on file not found', async () => { + process.env.SECRET_FILE = '/run/secrets/db_password' + const e: NodeJS.ErrnoException = new Error('no such file or directory') + e.code = 'ENOENT' + vi.mocked(readFile).mockRejectedValueOnce(e) + const res = await getSecret('SECRET') + expect(res).toBe('') + }) + + test('throws on permission denied', async () => { + process.env.SECRET_FILE = '/run/secrets/db_password' + const e: NodeJS.ErrnoException = new Error('permission denied') + e.code = 'EACCES' + vi.mocked(readFile).mockRejectedValueOnce(e) + await expect(getSecret('SECRET')).rejects.toThrow() + }) +}) diff --git a/test/lib/tables.ts b/test/lib/tables.ts index 9d750322..c4c934e7 100644 --- a/test/lib/tables.ts +++ b/test/lib/tables.ts @@ -1,16 +1,15 @@ +import { expect, test } from 'vitest' import { pgMeta } from './utils' const cleanNondet = (x: any) => { const { - data: { columns, grants, policies, primary_keys, relationships, ...rest2 }, + data: { columns, primary_keys, relationships, ...rest2 }, ...rest1 } = x return { data: { columns: columns.map(({ id, table_id, ...rest }: any) => rest), - grants: grants.map(({ table_id, ...rest }: any) => rest), - policies: policies.map(({ id, table_id, ...rest }: any) => rest), primary_keys: primary_keys.map(({ table_id, ...rest }: any) => rest), relationships: relationships.map(({ id, ...rest }: any) => rest), ...rest2, @@ -22,14 +21,12 @@ const cleanNondet = (x: any) => { test('list', async () => { const res = await pgMeta.tables.list() - const { columns, grants, policies, primary_keys, relationships, ...rest }: any = res.data?.find( + const { columns, primary_keys, relationships, ...rest }: any = res.data?.find( ({ name }) => name === 'users' ) expect({ columns: columns.map(({ id, table_id, ...rest }: any) => rest), - grants: grants.map(({ table_id, ...rest }: any) => rest), - policies: policies.map(({ id, table_id, ...rest }: any) => rest), primary_keys: primary_keys.map(({ table_id, ...rest }: any) => rest), relationships: relationships.map(({ id, ...rest }: any) => rest), ...rest, @@ -42,14 +39,15 @@ test('list', async () => { size: expect.any(String), }, ` - Object { + { "bytes": Any, - "columns": Array [ - Object { + "columns": [ + { + "check": null, "comment": null, "data_type": "bigint", "default_value": null, - "enums": Array [], + "enums": [], "format": "int8", "identity_generation": "BY DEFAULT", "is_generated": false, @@ -62,11 +60,12 @@ test('list', async () => { "schema": "public", "table": "users", }, - Object { + { + "check": null, "comment": null, "data_type": "text", "default_value": null, - "enums": Array [], + "enums": [], "format": "text", "identity_generation": null, "is_generated": false, @@ -79,11 +78,12 @@ test('list', async () => { "schema": "public", "table": "users", }, - Object { + { + "check": null, "comment": null, "data_type": "USER-DEFINED", "default_value": "'ACTIVE'::user_status", - "enums": Array [ + "enums": [ "ACTIVE", "INACTIVE", ], @@ -102,84 +102,82 @@ test('list', async () => { ], "comment": null, "dead_rows_estimate": Any, - "grants": Array [ - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "INSERT", - "schema": "public", - "table_name": "users", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "SELECT", - "schema": "public", - "table_name": "users", - "with_hierarchy": true, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "UPDATE", - "schema": "public", - "table_name": "users", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "DELETE", - "schema": "public", - "table_name": "users", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "TRUNCATE", + "id": Any, + "live_rows_estimate": Any, + "name": "users", + "primary_keys": [ + { + "name": "id", "schema": "public", "table_name": "users", - "with_hierarchy": false, }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "REFERENCES", - "schema": "public", - "table_name": "users", - "with_hierarchy": false, + ], + "relationships": [ + { + "constraint_name": "todos_user-id_fkey", + "source_column_name": "user-id", + "source_schema": "public", + "source_table_name": "todos", + "target_column_name": "id", + "target_table_name": "users", + "target_table_schema": "public", }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "TRIGGER", - "schema": "public", - "table_name": "users", - "with_hierarchy": false, + { + "constraint_name": "user_details_user_id_fkey", + "source_column_name": "user_id", + "source_schema": "public", + "source_table_name": "user_details", + "target_column_name": "id", + "target_table_name": "users", + "target_table_schema": "public", }, ], + "replica_identity": "DEFAULT", + "rls_enabled": false, + "rls_forced": false, + "schema": "public", + "size": Any, + } + ` + ) +}) + +test('list without columns', async () => { + const res = await pgMeta.tables.list({ includeColumns: false }) + + const { columns, primary_keys, relationships, ...rest }: any = res.data?.find( + ({ name }) => name === 'users' + ) + + expect({ + primary_keys: primary_keys.map(({ table_id, ...rest }: any) => rest), + relationships: relationships.map(({ id, ...rest }: any) => rest), + ...rest, + }).toMatchInlineSnapshot( + { + bytes: expect.any(Number), + dead_rows_estimate: expect.any(Number), + id: expect.any(Number), + live_rows_estimate: expect.any(Number), + size: expect.any(String), + }, + ` + { + "bytes": Any, + "comment": null, + "dead_rows_estimate": Any, "id": Any, "live_rows_estimate": Any, "name": "users", - "policies": Array [], - "primary_keys": Array [ - Object { + "primary_keys": [ + { "name": "id", "schema": "public", "table_name": "users", }, ], - "relationships": Array [ - Object { + "relationships": [ + { "constraint_name": "todos_user-id_fkey", "source_column_name": "user-id", "source_schema": "public", @@ -188,6 +186,15 @@ test('list', async () => { "target_table_name": "users", "target_table_schema": "public", }, + { + "constraint_name": "user_details_user_id_fkey", + "source_column_name": "user_id", + "source_schema": "public", + "source_table_name": "user_details", + "target_column_name": "id", + "target_table_name": "users", + "target_table_schema": "public", + }, ], "replica_identity": "DEFAULT", "rls_enabled": false, @@ -199,88 +206,57 @@ test('list', async () => { ) }) +test('list tables with included schemas', async () => { + let res = await pgMeta.tables.list({ + includedSchemas: ['public'], + }) + + expect(res.data?.length).toBeGreaterThan(0) + + res.data?.forEach((table) => { + expect(table.schema).toBe('public') + }) +}) + +test('list tables with excluded schemas', async () => { + let res = await pgMeta.tables.list({ + excludedSchemas: ['public'], + }) + + res.data?.forEach((table) => { + expect(table.schema).not.toBe('public') + }) +}) + +test('list tables with excluded schemas and include System Schemas', async () => { + let res = await pgMeta.tables.list({ + excludedSchemas: ['public'], + includeSystemSchemas: true, + }) + + expect(res.data?.length).toBeGreaterThan(0) + + res.data?.forEach((table) => { + expect(table.schema).not.toBe('public') + }) +}) + test('retrieve, create, update, delete', async () => { let res = await pgMeta.tables.create({ name: 'test', comment: 'foo' }) expect(cleanNondet(res)).toMatchInlineSnapshot( { data: { id: expect.any(Number) } }, ` - Object { - "data": Object { + { + "data": { "bytes": 0, - "columns": Array [], + "columns": [], "comment": "foo", "dead_rows_estimate": 0, - "grants": Array [ - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "INSERT", - "schema": "public", - "table_name": "test", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "SELECT", - "schema": "public", - "table_name": "test", - "with_hierarchy": true, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "UPDATE", - "schema": "public", - "table_name": "test", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "DELETE", - "schema": "public", - "table_name": "test", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "TRUNCATE", - "schema": "public", - "table_name": "test", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "REFERENCES", - "schema": "public", - "table_name": "test", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "TRIGGER", - "schema": "public", - "table_name": "test", - "with_hierarchy": false, - }, - ], "id": Any, "live_rows_estimate": 0, "name": "test", - "policies": Array [], - "primary_keys": Array [], - "relationships": Array [], + "primary_keys": [], + "relationships": [], "replica_identity": "DEFAULT", "rls_enabled": false, "rls_forced": false, @@ -295,83 +271,17 @@ test('retrieve, create, update, delete', async () => { expect(cleanNondet(res)).toMatchInlineSnapshot( { data: { id: expect.any(Number) } }, ` - Object { - "data": Object { + { + "data": { "bytes": 0, - "columns": Array [], + "columns": [], "comment": "foo", "dead_rows_estimate": 0, - "grants": Array [ - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "INSERT", - "schema": "public", - "table_name": "test", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "SELECT", - "schema": "public", - "table_name": "test", - "with_hierarchy": true, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "UPDATE", - "schema": "public", - "table_name": "test", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "DELETE", - "schema": "public", - "table_name": "test", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "TRUNCATE", - "schema": "public", - "table_name": "test", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "REFERENCES", - "schema": "public", - "table_name": "test", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "TRIGGER", - "schema": "public", - "table_name": "test", - "with_hierarchy": false, - }, - ], "id": Any, "live_rows_estimate": 0, "name": "test", - "policies": Array [], - "primary_keys": Array [], - "relationships": Array [], + "primary_keys": [], + "relationships": [], "replica_identity": "DEFAULT", "rls_enabled": false, "rls_forced": false, @@ -392,83 +302,17 @@ test('retrieve, create, update, delete', async () => { expect(cleanNondet(res)).toMatchInlineSnapshot( { data: { id: expect.any(Number) } }, ` - Object { - "data": Object { + { + "data": { "bytes": 0, - "columns": Array [], + "columns": [], "comment": "foo", "dead_rows_estimate": 0, - "grants": Array [ - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "INSERT", - "schema": "public", - "table_name": "test a", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "SELECT", - "schema": "public", - "table_name": "test a", - "with_hierarchy": true, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "UPDATE", - "schema": "public", - "table_name": "test a", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "DELETE", - "schema": "public", - "table_name": "test a", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "TRUNCATE", - "schema": "public", - "table_name": "test a", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "REFERENCES", - "schema": "public", - "table_name": "test a", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "TRIGGER", - "schema": "public", - "table_name": "test a", - "with_hierarchy": false, - }, - ], "id": Any, "live_rows_estimate": 0, "name": "test a", - "policies": Array [], - "primary_keys": Array [], - "relationships": Array [], + "primary_keys": [], + "relationships": [], "replica_identity": "NOTHING", "rls_enabled": true, "rls_forced": true, @@ -483,83 +327,17 @@ test('retrieve, create, update, delete', async () => { expect(cleanNondet(res)).toMatchInlineSnapshot( { data: { id: expect.any(Number) } }, ` - Object { - "data": Object { + { + "data": { "bytes": 0, - "columns": Array [], + "columns": [], "comment": "foo", "dead_rows_estimate": 0, - "grants": Array [ - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "INSERT", - "schema": "public", - "table_name": "test a", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "SELECT", - "schema": "public", - "table_name": "test a", - "with_hierarchy": true, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "UPDATE", - "schema": "public", - "table_name": "test a", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "DELETE", - "schema": "public", - "table_name": "test a", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "TRUNCATE", - "schema": "public", - "table_name": "test a", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "REFERENCES", - "schema": "public", - "table_name": "test a", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "TRIGGER", - "schema": "public", - "table_name": "test a", - "with_hierarchy": false, - }, - ], "id": Any, "live_rows_estimate": 0, "name": "test a", - "policies": Array [], - "primary_keys": Array [], - "relationships": Array [], + "primary_keys": [], + "relationships": [], "replica_identity": "NOTHING", "rls_enabled": true, "rls_forced": true, @@ -587,83 +365,17 @@ test('update with name unchanged', async () => { expect(cleanNondet(res)).toMatchInlineSnapshot( { data: { id: expect.any(Number) } }, ` - Object { - "data": Object { + { + "data": { "bytes": 0, - "columns": Array [], + "columns": [], "comment": null, "dead_rows_estimate": 0, - "grants": Array [ - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "INSERT", - "schema": "public", - "table_name": "t", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "SELECT", - "schema": "public", - "table_name": "t", - "with_hierarchy": true, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "UPDATE", - "schema": "public", - "table_name": "t", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "DELETE", - "schema": "public", - "table_name": "t", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "TRUNCATE", - "schema": "public", - "table_name": "t", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "REFERENCES", - "schema": "public", - "table_name": "t", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "TRIGGER", - "schema": "public", - "table_name": "t", - "with_hierarchy": false, - }, - ], "id": Any, "live_rows_estimate": 0, "name": "t", - "policies": Array [], - "primary_keys": Array [], - "relationships": Array [], + "primary_keys": [], + "relationships": [], "replica_identity": "DEFAULT", "rls_enabled": false, "rls_forced": false, @@ -682,83 +394,17 @@ test("allow ' in comments", async () => { expect(cleanNondet(res)).toMatchInlineSnapshot( { data: { id: expect.any(Number) } }, ` - Object { - "data": Object { + { + "data": { "bytes": 0, - "columns": Array [], + "columns": [], "comment": "'", "dead_rows_estimate": 0, - "grants": Array [ - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "INSERT", - "schema": "public", - "table_name": "t", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "SELECT", - "schema": "public", - "table_name": "t", - "with_hierarchy": true, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "UPDATE", - "schema": "public", - "table_name": "t", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "DELETE", - "schema": "public", - "table_name": "t", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "TRUNCATE", - "schema": "public", - "table_name": "t", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "REFERENCES", - "schema": "public", - "table_name": "t", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "TRIGGER", - "schema": "public", - "table_name": "t", - "with_hierarchy": false, - }, - ], "id": Any, "live_rows_estimate": 0, "name": "t", - "policies": Array [], - "primary_keys": Array [], - "relationships": Array [], + "primary_keys": [], + "relationships": [], "replica_identity": "DEFAULT", "rls_enabled": false, "rls_forced": false, @@ -790,15 +436,16 @@ test('primary keys', async () => { }, }, ` - Object { - "data": Object { + { + "data": { "bytes": Any, - "columns": Array [ - Object { + "columns": [ + { + "check": null, "comment": null, "data_type": "bigint", "default_value": null, - "enums": Array [], + "enums": [], "format": "int8", "identity_generation": null, "is_generated": false, @@ -811,11 +458,12 @@ test('primary keys', async () => { "schema": "public", "table": "t", }, - Object { + { + "check": null, "comment": null, "data_type": "text", "default_value": null, - "enums": Array [], + "enums": [], "format": "text", "identity_generation": null, "is_generated": false, @@ -831,88 +479,22 @@ test('primary keys', async () => { ], "comment": null, "dead_rows_estimate": Any, - "grants": Array [ - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "INSERT", - "schema": "public", - "table_name": "t", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "SELECT", - "schema": "public", - "table_name": "t", - "with_hierarchy": true, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "UPDATE", - "schema": "public", - "table_name": "t", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "DELETE", - "schema": "public", - "table_name": "t", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "TRUNCATE", - "schema": "public", - "table_name": "t", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "REFERENCES", - "schema": "public", - "table_name": "t", - "with_hierarchy": false, - }, - Object { - "grantee": "postgres", - "grantor": "postgres", - "is_grantable": true, - "privilege_type": "TRIGGER", - "schema": "public", - "table_name": "t", - "with_hierarchy": false, - }, - ], "id": Any, "live_rows_estimate": Any, "name": "t", - "policies": Array [], - "primary_keys": Array [ - Object { + "primary_keys": [ + { "name": "c", "schema": "public", "table_name": "t", }, - Object { + { "name": "cc", "schema": "public", "table_name": "t", }, ], - "relationships": Array [], + "relationships": [], "replica_identity": "DEFAULT", "rls_enabled": false, "rls_forced": false, diff --git a/test/lib/triggers.ts b/test/lib/triggers.ts index 27fe32b7..beb5d63d 100644 --- a/test/lib/triggers.ts +++ b/test/lib/triggers.ts @@ -1,3 +1,4 @@ +import { expect, test } from 'vitest' import { pgMeta } from './utils' test('retrieve, create, update, delete', async () => { @@ -16,15 +17,15 @@ test('retrieve, create, update, delete', async () => { expect(res).toMatchInlineSnapshot( { data: { id: expect.any(Number), table_id: expect.any(Number) } }, ` - Object { - "data": Object { + { + "data": { "activation": "AFTER", "condition": "(old.* IS DISTINCT FROM new.*)", "enabled_mode": "ORIGIN", - "events": Array [ + "events": [ "UPDATE", ], - "function_args": Array [ + "function_args": [ "test1", "test2", ], @@ -45,15 +46,15 @@ test('retrieve, create, update, delete', async () => { expect(res).toMatchInlineSnapshot( { data: { id: expect.any(Number), table_id: expect.any(Number) } }, ` - Object { - "data": Object { + { + "data": { "activation": "AFTER", "condition": "(old.* IS DISTINCT FROM new.*)", "enabled_mode": "ORIGIN", - "events": Array [ + "events": [ "UPDATE", ], - "function_args": Array [ + "function_args": [ "test1", "test2", ], @@ -77,15 +78,15 @@ test('retrieve, create, update, delete', async () => { expect(res).toMatchInlineSnapshot( { data: { id: expect.any(Number), table_id: expect.any(Number) } }, ` - Object { - "data": Object { + { + "data": { "activation": "AFTER", "condition": "(old.* IS DISTINCT FROM new.*)", "enabled_mode": "DISABLED", - "events": Array [ + "events": [ "UPDATE", ], - "function_args": Array [ + "function_args": [ "test1", "test2", ], @@ -108,15 +109,15 @@ test('retrieve, create, update, delete', async () => { expect(res).toMatchInlineSnapshot( { data: { id: expect.any(Number), table_id: expect.any(Number) } }, ` - Object { - "data": Object { + { + "data": { "activation": "AFTER", "condition": "(old.* IS DISTINCT FROM new.*)", "enabled_mode": "REPLICA", - "events": Array [ + "events": [ "UPDATE", ], - "function_args": Array [ + "function_args": [ "test1", "test2", ], @@ -137,15 +138,15 @@ test('retrieve, create, update, delete', async () => { expect(res).toMatchInlineSnapshot( { data: { id: expect.any(Number), table_id: expect.any(Number) } }, ` - Object { - "data": Object { + { + "data": { "activation": "AFTER", "condition": "(old.* IS DISTINCT FROM new.*)", "enabled_mode": "REPLICA", - "events": Array [ + "events": [ "UPDATE", ], - "function_args": Array [ + "function_args": [ "test1", "test2", ], @@ -187,17 +188,17 @@ test('multi event', async () => { expect(res).toMatchInlineSnapshot( { data: { id: expect.any(Number), table_id: expect.any(Number) } }, ` - Object { - "data": Object { + { + "data": { "activation": "AFTER", "condition": null, "enabled_mode": "ORIGIN", - "events": Array [ + "events": [ "INSERT", "DELETE", "UPDATE", ], - "function_args": Array [ + "function_args": [ "test1", "test2", ], @@ -216,3 +217,98 @@ test('multi event', async () => { ) await pgMeta.triggers.remove(res.data!.id) }) + +test('triggers with the same name on different schemas', async () => { + await pgMeta.query(` +create function tr_f() returns trigger language plpgsql as 'begin end'; +create schema s1; create table s1.t(); create trigger tr before insert on s1.t execute function tr_f(); +create schema s2; create table s2.t(); create trigger tr before insert on s2.t execute function tr_f(); +`) + + const res = await pgMeta.triggers.list() + const triggers = res.data?.map(({ id, table_id, ...trigger }) => trigger) + expect(triggers).toMatchInlineSnapshot(` + [ + { + "activation": "BEFORE", + "condition": null, + "enabled_mode": "ORIGIN", + "events": [ + "INSERT", + ], + "function_args": [], + "function_name": "tr_f", + "function_schema": "public", + "name": "tr", + "orientation": "STATEMENT", + "schema": "s1", + "table": "t", + }, + { + "activation": "BEFORE", + "condition": null, + "enabled_mode": "ORIGIN", + "events": [ + "INSERT", + ], + "function_args": [], + "function_name": "tr_f", + "function_schema": "public", + "name": "tr", + "orientation": "STATEMENT", + "schema": "s2", + "table": "t", + }, + ] + `) + + await pgMeta.query('drop schema s1 cascade; drop schema s2 cascade;') +}) + +test('triggers on capitalized schema and table names', async () => { + await pgMeta.query(` +CREATE SCHEMA "MySchema"; +CREATE TABLE "MySchema"."MyTable" ( + id SERIAL PRIMARY KEY, + name TEXT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP +); +CREATE OR REPLACE FUNCTION "MySchema"."my_trigger_function"() +RETURNS TRIGGER AS $$ +BEGIN + NEW.updated_at := CURRENT_TIMESTAMP; + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER "my_trigger" +BEFORE INSERT ON "MySchema"."MyTable" +FOR EACH ROW +EXECUTE FUNCTION "MySchema"."my_trigger_function"(); +`) + + const res = await pgMeta.triggers.list() + const triggers = res.data?.map(({ id, table_id, ...trigger }) => trigger) + expect(triggers).toMatchInlineSnapshot(` + [ + { + "activation": "BEFORE", + "condition": null, + "enabled_mode": "ORIGIN", + "events": [ + "INSERT", + ], + "function_args": [], + "function_name": "my_trigger_function", + "function_schema": "MySchema", + "name": "my_trigger", + "orientation": "ROW", + "schema": "MySchema", + "table": "MyTable", + }, + ] + `) + + await pgMeta.query('drop schema "MySchema" cascade;') +}) diff --git a/test/lib/types.ts b/test/lib/types.ts index 43f9b260..fb8c8f30 100644 --- a/test/lib/types.ts +++ b/test/lib/types.ts @@ -1,3 +1,4 @@ +import { expect, test } from 'vitest' import { pgMeta } from './utils' test('list', async () => { @@ -5,9 +6,10 @@ test('list', async () => { expect(res.data?.find(({ name }) => name === 'user_status')).toMatchInlineSnapshot( { id: expect.any(Number) }, ` - Object { + { + "attributes": [], "comment": null, - "enums": Array [ + "enums": [ "ACTIVE", "INACTIVE", ], @@ -19,3 +21,100 @@ test('list', async () => { ` ) }) + +test('list types with included schemas', async () => { + let res = await pgMeta.types.list({ + includedSchemas: ['public'], + }) + + expect(res.data?.length).toBeGreaterThan(0) + + res.data?.forEach((type) => { + expect(type.schema).toBe('public') + }) +}) + +test('list types with excluded schemas', async () => { + let res = await pgMeta.types.list({ + excludedSchemas: ['public'], + }) + + res.data?.forEach((type) => { + expect(type.schema).not.toBe('public') + }) +}) + +test('list types with excluded schemas and include System Schemas', async () => { + let res = await pgMeta.types.list({ + excludedSchemas: ['public'], + includeSystemSchemas: true, + }) + + expect(res.data?.length).toBeGreaterThan(0) + + res.data?.forEach((type) => { + expect(type.schema).not.toBe('public') + }) +}) + +test('list types with include Table Types', async () => { + const res = await pgMeta.types.list({ + includeTableTypes: true, + }) + + expect(res.data?.find(({ name }) => name === 'todos')).toMatchInlineSnapshot( + { id: expect.any(Number) }, + ` + { + "attributes": [], + "comment": null, + "enums": [], + "format": "todos", + "id": Any, + "name": "todos", + "schema": "public", + } + ` + ) +}) + +test('list types without Table Types', async () => { + const res = await pgMeta.types.list({ + includeTableTypes: false, + }) + + res.data?.forEach((type) => { + expect(type.name).not.toBe('todos') + }) +}) + +test('composite type attributes', async () => { + await pgMeta.query(`create type test_composite as (id int8, data text);`) + + const res = await pgMeta.types.list() + expect(res.data?.find(({ name }) => name === 'test_composite')).toMatchInlineSnapshot( + { id: expect.any(Number) }, + ` + { + "attributes": [ + { + "name": "id", + "type_id": 20, + }, + { + "name": "data", + "type_id": 25, + }, + ], + "comment": null, + "enums": [], + "format": "test_composite", + "id": Any, + "name": "test_composite", + "schema": "public", + } + ` + ) + + await pgMeta.query(`drop type test_composite;`) +}) diff --git a/test/lib/utils.ts b/test/lib/utils.ts index 18e8a3ec..e4d48fe7 100644 --- a/test/lib/utils.ts +++ b/test/lib/utils.ts @@ -1,3 +1,4 @@ +import { afterAll } from 'vitest' import { PostgresMeta } from '../../src/lib' export const pgMeta = new PostgresMeta({ diff --git a/test/lib/version.ts b/test/lib/version.ts index c44bfaa6..9309fe16 100644 --- a/test/lib/version.ts +++ b/test/lib/version.ts @@ -1,3 +1,4 @@ +import { expect, test } from 'vitest' import { pgMeta } from './utils' test('retrieve', async () => { @@ -12,8 +13,8 @@ test('retrieve', async () => { }, }, ` - Object { - "data": Object { + { + "data": { "active_connections": Any, "max_connections": Any, "version": StringMatching /\\^PostgreSQL/, diff --git a/test/lib/views.ts b/test/lib/views.ts index 63ccc5c9..275eb4a3 100644 --- a/test/lib/views.ts +++ b/test/lib/views.ts @@ -1,3 +1,4 @@ +import { expect, test } from 'vitest' import { pgMeta } from './utils' test('list', async () => { @@ -5,12 +6,174 @@ test('list', async () => { expect(res.data?.find(({ name }) => name === 'todos_view')).toMatchInlineSnapshot( { id: expect.any(Number) }, ` - Object { + { + "columns": [ + { + "check": null, + "comment": null, + "data_type": "bigint", + "default_value": null, + "enums": [], + "format": "int8", + "id": "16423.1", + "identity_generation": null, + "is_generated": false, + "is_identity": false, + "is_nullable": true, + "is_unique": false, + "is_updatable": true, + "name": "id", + "ordinal_position": 1, + "schema": "public", + "table": "todos_view", + "table_id": 16423, + }, + { + "check": null, + "comment": null, + "data_type": "text", + "default_value": null, + "enums": [], + "format": "text", + "id": "16423.2", + "identity_generation": null, + "is_generated": false, + "is_identity": false, + "is_nullable": true, + "is_unique": false, + "is_updatable": true, + "name": "details", + "ordinal_position": 2, + "schema": "public", + "table": "todos_view", + "table_id": 16423, + }, + { + "check": null, + "comment": null, + "data_type": "bigint", + "default_value": null, + "enums": [], + "format": "int8", + "id": "16423.3", + "identity_generation": null, + "is_generated": false, + "is_identity": false, + "is_nullable": true, + "is_unique": false, + "is_updatable": true, + "name": "user-id", + "ordinal_position": 3, + "schema": "public", + "table": "todos_view", + "table_id": 16423, + }, + ], "comment": null, "id": Any, + "is_updatable": true, "name": "todos_view", "schema": "public", } ` ) }) + +test('list without columns', async () => { + const res = await pgMeta.views.list({ includeColumns: false }) + expect(res.data?.find(({ name }) => name === 'todos_view')).toMatchInlineSnapshot( + { + id: expect.any(Number), + }, + ` + { + "comment": null, + "id": Any, + "is_updatable": true, + "name": "todos_view", + "schema": "public", + } + ` + ) +}) + +test('retrieve', async () => { + const res = await pgMeta.views.retrieve({ schema: 'public', name: 'todos_view' }) + expect(res).toMatchInlineSnapshot( + { data: { id: expect.any(Number) } }, + ` + { + "data": { + "columns": [ + { + "check": null, + "comment": null, + "data_type": "bigint", + "default_value": null, + "enums": [], + "format": "int8", + "id": "16423.1", + "identity_generation": null, + "is_generated": false, + "is_identity": false, + "is_nullable": true, + "is_unique": false, + "is_updatable": true, + "name": "id", + "ordinal_position": 1, + "schema": "public", + "table": "todos_view", + "table_id": 16423, + }, + { + "check": null, + "comment": null, + "data_type": "text", + "default_value": null, + "enums": [], + "format": "text", + "id": "16423.2", + "identity_generation": null, + "is_generated": false, + "is_identity": false, + "is_nullable": true, + "is_unique": false, + "is_updatable": true, + "name": "details", + "ordinal_position": 2, + "schema": "public", + "table": "todos_view", + "table_id": 16423, + }, + { + "check": null, + "comment": null, + "data_type": "bigint", + "default_value": null, + "enums": [], + "format": "int8", + "id": "16423.3", + "identity_generation": null, + "is_generated": false, + "is_identity": false, + "is_nullable": true, + "is_unique": false, + "is_updatable": true, + "name": "user-id", + "ordinal_position": 3, + "schema": "public", + "table": "todos_view", + "table_id": 16423, + }, + ], + "comment": null, + "id": Any, + "is_updatable": true, + "name": "todos_view", + "schema": "public", + }, + "error": null, + } + ` + ) +}) diff --git a/test/server/column-privileges.ts b/test/server/column-privileges.ts new file mode 100644 index 00000000..5237f264 --- /dev/null +++ b/test/server/column-privileges.ts @@ -0,0 +1,365 @@ +import { expect, test } from 'vitest' +import { PostgresColumnPrivileges } from '../../src/lib/types' +import { app } from './utils' + +test('list column privileges', async () => { + const res = await app.inject({ method: 'GET', path: '/column-privileges' }) + const column = res + .json() + .find( + ({ relation_schema, relation_name, column_name }) => + relation_schema === 'public' && relation_name === 'todos' && column_name === 'id' + )! + // We don't guarantee order of privileges, but we want to keep the snapshots consistent. + column.privileges.sort((a, b) => JSON.stringify(a).localeCompare(JSON.stringify(b))) + expect(column).toMatchInlineSnapshot( + { column_id: expect.stringMatching(/^\d+\.\d+$/) }, + ` + { + "column_id": StringMatching /\\^\\\\d\\+\\\\\\.\\\\d\\+\\$/, + "column_name": "id", + "privileges": [ + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "INSERT", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "REFERENCES", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "SELECT", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "UPDATE", + }, + ], + "relation_name": "todos", + "relation_schema": "public", + } + ` + ) +}) + +test('revoke & grant column privileges', async () => { + let res = await app.inject({ method: 'GET', path: '/column-privileges' }) + const { column_id } = res + .json() + .find( + ({ relation_schema, relation_name, column_name }) => + relation_schema === 'public' && relation_name === 'todos' && column_name === 'id' + )! + + res = await app.inject({ + method: 'POST', + path: '/query', + payload: { + query: `create role r;`, + }, + }) + if (res.json().error) { + throw new Error(res.payload) + } + + res = await app.inject({ + method: 'POST', + path: '/column-privileges', + payload: [ + { + column_id, + grantee: 'r', + privilege_type: 'ALL', + }, + ], + }) + let privs = res.json() + expect(privs.length).toBe(1) + expect(privs[0]).toMatchInlineSnapshot( + { column_id: expect.stringMatching(/^\d+\.\d+$/) }, + ` + { + "column_id": StringMatching /\\^\\\\d\\+\\\\\\.\\\\d\\+\\$/, + "column_name": "id", + "privileges": [ + { + "grantee": "r", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "UPDATE", + }, + { + "grantee": "r", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "SELECT", + }, + { + "grantee": "r", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "REFERENCES", + }, + { + "grantee": "r", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "INSERT", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "UPDATE", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "SELECT", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "REFERENCES", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "INSERT", + }, + ], + "relation_name": "todos", + "relation_schema": "public", + } + ` + ) + + res = await app.inject({ + method: 'DELETE', + path: '/column-privileges', + payload: [ + { + column_id, + grantee: 'r', + privilege_type: 'ALL', + }, + ], + }) + privs = res.json() + expect(privs.length).toBe(1) + expect(privs[0]).toMatchInlineSnapshot( + { column_id: expect.stringMatching(/^\d+\.\d+$/) }, + ` + { + "column_id": StringMatching /\\^\\\\d\\+\\\\\\.\\\\d\\+\\$/, + "column_name": "id", + "privileges": [ + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "UPDATE", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "SELECT", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "REFERENCES", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "INSERT", + }, + ], + "relation_name": "todos", + "relation_schema": "public", + } + ` + ) + + res = await app.inject({ + method: 'POST', + path: '/query', + payload: { + query: `drop role r;`, + }, + }) + if (res.json().error) { + throw new Error(res.payload) + } +}) + +test('revoke & grant column privileges w/ quoted column name', async () => { + let res = await app.inject({ + method: 'POST', + path: '/query', + payload: { + query: `create role r; create table "t 1"("c 1" int8);`, + }, + }) + if (res.json().error) { + throw new Error(res.payload) + } + + res = await app.inject({ method: 'GET', path: '/column-privileges' }) + const { column_id } = res + .json() + .find(({ relation_name, column_name }) => relation_name === 't 1' && column_name === 'c 1')! + + res = await app.inject({ + method: 'POST', + path: '/column-privileges', + payload: [ + { + column_id, + grantee: 'r', + privilege_type: 'ALL', + }, + ], + }) + let privs = res.json() + expect(privs.length).toBe(1) + expect(privs[0]).toMatchInlineSnapshot( + { column_id: expect.stringMatching(/^\d+\.\d+$/) }, + ` + { + "column_id": StringMatching /\\^\\\\d\\+\\\\\\.\\\\d\\+\\$/, + "column_name": "c 1", + "privileges": [ + { + "grantee": "r", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "UPDATE", + }, + { + "grantee": "r", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "SELECT", + }, + { + "grantee": "r", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "REFERENCES", + }, + { + "grantee": "r", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "INSERT", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "UPDATE", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "SELECT", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "REFERENCES", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "INSERT", + }, + ], + "relation_name": "t 1", + "relation_schema": "public", + } + ` + ) + + res = await app.inject({ + method: 'DELETE', + path: '/column-privileges', + payload: [ + { + column_id, + grantee: 'r', + privilege_type: 'ALL', + }, + ], + }) + privs = res.json() + expect(privs.length).toBe(1) + expect(privs[0]).toMatchInlineSnapshot( + { column_id: expect.stringMatching(/^\d+\.\d+$/) }, + ` + { + "column_id": StringMatching /\\^\\\\d\\+\\\\\\.\\\\d\\+\\$/, + "column_name": "c 1", + "privileges": [ + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "UPDATE", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "SELECT", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "REFERENCES", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "INSERT", + }, + ], + "relation_name": "t 1", + "relation_schema": "public", + } + ` + ) + + res = await app.inject({ + method: 'POST', + path: '/query', + payload: { + query: `drop role r; drop table "t 1";`, + }, + }) + if (res.json().error) { + throw new Error(res.payload) + } +}) diff --git a/test/server/indexes.ts b/test/server/indexes.ts new file mode 100644 index 00000000..b3fb7f0c --- /dev/null +++ b/test/server/indexes.ts @@ -0,0 +1,106 @@ +import { expect, test } from 'vitest' +import { PostgresIndex } from '../../src/lib/types' +import { app } from './utils' + +test('list indexes', async () => { + const res = await app.inject({ method: 'GET', path: '/indexes' }) + const index = res + .json() + .find( + ({ index_definition }) => + index_definition === 'CREATE UNIQUE INDEX users_pkey ON public.users USING btree (id)' + )! + expect(index).toMatchInlineSnapshot( + ` + { + "access_method": "btree", + "check_xmin": false, + "class": [ + 3124, + ], + "collation": [ + 0, + ], + "comment": null, + "id": 16399, + "index_attributes": [ + { + "attribute_name": "id", + "attribute_number": 1, + "data_type": "bigint", + }, + ], + "index_definition": "CREATE UNIQUE INDEX users_pkey ON public.users USING btree (id)", + "index_predicate": null, + "is_clustered": false, + "is_exclusion": false, + "is_immediate": true, + "is_live": true, + "is_primary": true, + "is_ready": true, + "is_replica_identity": false, + "is_unique": true, + "is_valid": true, + "key_attributes": [ + 1, + ], + "number_of_attributes": 1, + "number_of_key_attributes": 1, + "options": [ + 0, + ], + "schema": "public", + "table_id": 16393, + } + ` + ) +}) + +test('retrieve index', async () => { + const res = await app.inject({ method: 'GET', path: '/indexes/16399' }) + const index = res.json() + expect(index).toMatchInlineSnapshot( + ` + { + "access_method": "btree", + "check_xmin": false, + "class": [ + 3124, + ], + "collation": [ + 0, + ], + "comment": null, + "id": 16399, + "index_attributes": [ + { + "attribute_name": "id", + "attribute_number": 1, + "data_type": "bigint", + }, + ], + "index_definition": "CREATE UNIQUE INDEX users_pkey ON public.users USING btree (id)", + "index_predicate": null, + "is_clustered": false, + "is_exclusion": false, + "is_immediate": true, + "is_live": true, + "is_primary": true, + "is_ready": true, + "is_replica_identity": false, + "is_unique": true, + "is_valid": true, + "key_attributes": [ + 1, + ], + "number_of_attributes": 1, + "number_of_key_attributes": 1, + "options": [ + 0, + ], + "schema": "public", + "table_id": 16393, + } + ` + ) +}) diff --git a/test/server/materialized-views.ts b/test/server/materialized-views.ts new file mode 100644 index 00000000..8799a6a9 --- /dev/null +++ b/test/server/materialized-views.ts @@ -0,0 +1,102 @@ +import { expect, test } from 'vitest' +import { app } from './utils' + +const cleanNondetFromBody = (x: T) => { + const cleanNondet = ({ id, columns, ...rest }: any) => { + const cleaned = rest + if (columns) { + cleaned.columns = columns.map(({ id, table_id, ...rest }: any) => rest) + } + return cleaned + } + + return (Array.isArray(x) ? x.map(cleanNondet) : cleanNondet(x)) as T +} + +test('materialized views', async () => { + const { body } = await app.inject({ method: 'GET', path: '/materialized-views' }) + expect(cleanNondetFromBody(JSON.parse(body))).toMatchInlineSnapshot(` + [ + { + "comment": null, + "is_populated": true, + "name": "todos_matview", + "schema": "public", + }, + ] + `) +}) + +test('materialized views with columns', async () => { + const { body } = await app.inject({ + method: 'GET', + path: '/materialized-views', + query: { include_columns: 'true' }, + }) + expect(cleanNondetFromBody(JSON.parse(body))).toMatchInlineSnapshot(` + [ + { + "columns": [ + { + "check": null, + "comment": null, + "data_type": "bigint", + "default_value": null, + "enums": [], + "format": "int8", + "identity_generation": null, + "is_generated": false, + "is_identity": false, + "is_nullable": true, + "is_unique": false, + "is_updatable": false, + "name": "id", + "ordinal_position": 1, + "schema": "public", + "table": "todos_matview", + }, + { + "check": null, + "comment": null, + "data_type": "text", + "default_value": null, + "enums": [], + "format": "text", + "identity_generation": null, + "is_generated": false, + "is_identity": false, + "is_nullable": true, + "is_unique": false, + "is_updatable": false, + "name": "details", + "ordinal_position": 2, + "schema": "public", + "table": "todos_matview", + }, + { + "check": null, + "comment": null, + "data_type": "bigint", + "default_value": null, + "enums": [], + "format": "int8", + "identity_generation": null, + "is_generated": false, + "is_identity": false, + "is_nullable": true, + "is_unique": false, + "is_updatable": false, + "name": "user-id", + "ordinal_position": 3, + "schema": "public", + "table": "todos_matview", + }, + ], + "comment": null, + "is_populated": true, + "name": "todos_matview", + "schema": "public", + }, + ] + `) +}) diff --git a/test/server/query-timeout.ts b/test/server/query-timeout.ts new file mode 100644 index 00000000..47554afc --- /dev/null +++ b/test/server/query-timeout.ts @@ -0,0 +1,73 @@ +import { expect, test, describe } from 'vitest' +import { app } from './utils' +import { pgMeta } from '../lib/utils' + +const TIMEOUT = (Number(process.env.PG_QUERY_TIMEOUT_SECS) ?? 10) + 2 +const STATEMENT_TIMEOUT = (Number(process.env.PG_QUERY_TIMEOUT_SECS) ?? 10) + 1 + +describe('test query timeout', () => { + test( + `query timeout after ${TIMEOUT}s and connection cleanup`, + async () => { + const query = `SELECT pg_sleep(${TIMEOUT + 10});` + // Execute a query that will sleep for 10 seconds + const res = await app.inject({ + method: 'POST', + path: '/query', + query: `statementTimeoutSecs=${STATEMENT_TIMEOUT}`, + payload: { + query, + }, + }) + + // Check that we get the proper timeout error response + expect(res.statusCode).toBe(408) // Request Timeout + expect(res.json()).toMatchObject({ + error: expect.stringContaining('Query read timeout'), + }) + // wait one second for the statement timeout to take effect + await new Promise((resolve) => setTimeout(resolve, 1000)) + + // Verify that the connection has been cleaned up by checking active connections + const connectionsRes = await pgMeta.query(` + SELECT * FROM pg_stat_activity where application_name = 'postgres-meta 0.0.0-automated' and query ILIKE '%${query}%'; + `) + + // Should have no active connections except for our current query + expect(connectionsRes.data).toHaveLength(0) + }, + TIMEOUT * 1000 + ) + + test( + 'query without timeout parameter should not have timeout', + async () => { + const query = `SELECT pg_sleep(${TIMEOUT + 10});` + // Execute a query that will sleep for 10 seconds without specifying timeout + const res = await app.inject({ + method: 'POST', + path: '/query', + payload: { + query, + }, + }) + + // Check that we get the proper timeout error response + expect(res.statusCode).toBe(408) // Request Timeout + expect(res.json()).toMatchObject({ + error: expect.stringContaining('Query read timeout'), + }) + // wait one second + await new Promise((resolve) => setTimeout(resolve, 1000)) + + // Verify that the connection has not been cleaned up sinice there is no statementTimetout + const connectionsRes = await pgMeta.query(` + SELECT * FROM pg_stat_activity where application_name = 'postgres-meta 0.0.0-automated' and query ILIKE '%${query}%'; + `) + + // Should have no active connections except for our current query + expect(connectionsRes.data).toHaveLength(1) + }, + TIMEOUT * 1000 + ) +}) diff --git a/test/server/query.ts b/test/server/query.ts new file mode 100644 index 00000000..2b4bc2ba --- /dev/null +++ b/test/server/query.ts @@ -0,0 +1,753 @@ +import { expect, test } from 'vitest' +import { app } from './utils' + +test('query', async () => { + const res = await app.inject({ + method: 'POST', + path: '/query', + payload: { query: 'SELECT * FROM users' }, + }) + expect(res.json()).toMatchInlineSnapshot(` + [ + { + "id": 1, + "name": "Joe Bloggs", + "status": "ACTIVE", + }, + { + "id": 2, + "name": "Jane Doe", + "status": "ACTIVE", + }, + ] + `) +}) + +test('error', async () => { + const res = await app.inject({ + method: 'POST', + path: '/query', + payload: { query: 'DROP TABLE missing_table' }, + }) + expect(res.json()).toMatchInlineSnapshot(` + { + "code": "42P01", + "error": "ERROR: 42P01: table "missing_table" does not exist + ", + "file": "tablecmds.c", + "formattedError": "ERROR: 42P01: table "missing_table" does not exist + ", + "length": 108, + "line": "1259", + "message": "table "missing_table" does not exist", + "name": "error", + "routine": "DropErrorMsgNonExistent", + "severity": "ERROR", + } + `) +}) + +test('parser select statements', async () => { + const res = await app.inject({ + method: 'POST', + path: '/query/parse', + payload: { query: 'SELECT id, name FROM users where user_id = 1234' }, + }) + expect(res.json()).toMatchInlineSnapshot(` + [ + { + "RawStmt": { + "stmt": { + "SelectStmt": { + "fromClause": [ + { + "RangeVar": { + "inh": true, + "location": 21, + "relname": "users", + "relpersistence": "p", + }, + }, + ], + "limitOption": "LIMIT_OPTION_DEFAULT", + "op": "SETOP_NONE", + "targetList": [ + { + "ResTarget": { + "location": 7, + "val": { + "ColumnRef": { + "fields": [ + { + "String": { + "str": "id", + }, + }, + ], + "location": 7, + }, + }, + }, + }, + { + "ResTarget": { + "location": 11, + "val": { + "ColumnRef": { + "fields": [ + { + "String": { + "str": "name", + }, + }, + ], + "location": 11, + }, + }, + }, + }, + ], + "whereClause": { + "A_Expr": { + "kind": "AEXPR_OP", + "lexpr": { + "ColumnRef": { + "fields": [ + { + "String": { + "str": "user_id", + }, + }, + ], + "location": 33, + }, + }, + "location": 41, + "name": [ + { + "String": { + "str": "=", + }, + }, + ], + "rexpr": { + "A_Const": { + "location": 43, + "val": { + "Integer": { + "ival": 1234, + }, + }, + }, + }, + }, + }, + }, + }, + "stmt_location": 0, + }, + }, + ] + `) +}) + +test('parser comments', async () => { + const res = await app.inject({ + method: 'POST', + path: '/query/parse', + payload: { + query: ` +-- test comments +`, + }, + }) + expect(res.json()).toMatchInlineSnapshot(`[]`) +}) + +test('parser create schema', async () => { + const res = await app.inject({ + method: 'POST', + path: '/query/parse', + payload: { + query: ` +create schema if not exists test_schema; +`, + }, + }) + expect(res.json()).toMatchInlineSnapshot(` + [ + { + "RawStmt": { + "stmt": { + "CreateSchemaStmt": { + "if_not_exists": true, + "schemaname": "test_schema", + }, + }, + "stmt_len": 40, + "stmt_location": 0, + }, + }, + ] + `) +}) + +test('parser create statements', async () => { + const res = await app.inject({ + method: 'POST', + path: '/query/parse', + payload: { + query: ` +CREATE TABLE table_name ( + id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + inserted_at timestamp with time zone DEFAULT timezone('utc'::text, now()) NOT NULL, + updated_at timestamp with time zone DEFAULT timezone('utc'::text, now()) NOT NULL, + data jsonb, + name text +); +`, + }, + }) + expect(res.json()).toMatchInlineSnapshot(` + [ + { + "RawStmt": { + "stmt": { + "CreateStmt": { + "oncommit": "ONCOMMIT_NOOP", + "relation": { + "inh": true, + "location": 14, + "relname": "table_name", + "relpersistence": "p", + }, + "tableElts": [ + { + "ColumnDef": { + "colname": "id", + "constraints": [ + { + "Constraint": { + "contype": "CONSTR_IDENTITY", + "generated_when": "d", + "location": 39, + }, + }, + { + "Constraint": { + "contype": "CONSTR_PRIMARY", + "location": 72, + }, + }, + ], + "is_local": true, + "location": 29, + "typeName": { + "location": 32, + "names": [ + { + "String": { + "str": "pg_catalog", + }, + }, + { + "String": { + "str": "int8", + }, + }, + ], + "typemod": -1, + }, + }, + }, + { + "ColumnDef": { + "colname": "inserted_at", + "constraints": [ + { + "Constraint": { + "contype": "CONSTR_DEFAULT", + "location": 124, + "raw_expr": { + "FuncCall": { + "args": [ + { + "TypeCast": { + "arg": { + "A_Const": { + "location": 141, + "val": { + "String": { + "str": "utc", + }, + }, + }, + }, + "location": 146, + "typeName": { + "location": 148, + "names": [ + { + "String": { + "str": "text", + }, + }, + ], + "typemod": -1, + }, + }, + }, + { + "FuncCall": { + "funcname": [ + { + "String": { + "str": "now", + }, + }, + ], + "location": 154, + }, + }, + ], + "funcname": [ + { + "String": { + "str": "timezone", + }, + }, + ], + "location": 132, + }, + }, + }, + }, + { + "Constraint": { + "contype": "CONSTR_NOTNULL", + "location": 161, + }, + }, + ], + "is_local": true, + "location": 87, + "typeName": { + "location": 99, + "names": [ + { + "String": { + "str": "pg_catalog", + }, + }, + { + "String": { + "str": "timestamptz", + }, + }, + ], + "typemod": -1, + }, + }, + }, + { + "ColumnDef": { + "colname": "updated_at", + "constraints": [ + { + "Constraint": { + "contype": "CONSTR_DEFAULT", + "location": 209, + "raw_expr": { + "FuncCall": { + "args": [ + { + "TypeCast": { + "arg": { + "A_Const": { + "location": 226, + "val": { + "String": { + "str": "utc", + }, + }, + }, + }, + "location": 231, + "typeName": { + "location": 233, + "names": [ + { + "String": { + "str": "text", + }, + }, + ], + "typemod": -1, + }, + }, + }, + { + "FuncCall": { + "funcname": [ + { + "String": { + "str": "now", + }, + }, + ], + "location": 239, + }, + }, + ], + "funcname": [ + { + "String": { + "str": "timezone", + }, + }, + ], + "location": 217, + }, + }, + }, + }, + { + "Constraint": { + "contype": "CONSTR_NOTNULL", + "location": 246, + }, + }, + ], + "is_local": true, + "location": 173, + "typeName": { + "location": 184, + "names": [ + { + "String": { + "str": "pg_catalog", + }, + }, + { + "String": { + "str": "timestamptz", + }, + }, + ], + "typemod": -1, + }, + }, + }, + { + "ColumnDef": { + "colname": "data", + "is_local": true, + "location": 258, + "typeName": { + "location": 263, + "names": [ + { + "String": { + "str": "jsonb", + }, + }, + ], + "typemod": -1, + }, + }, + }, + { + "ColumnDef": { + "colname": "name", + "is_local": true, + "location": 272, + "typeName": { + "location": 277, + "names": [ + { + "String": { + "str": "text", + }, + }, + ], + "typemod": -1, + }, + }, + }, + ], + }, + }, + "stmt_len": 283, + "stmt_location": 0, + }, + }, + ] + `) + + const deparse = await app.inject({ + method: 'POST', + path: '/query/deparse', + payload: { ast: res.json() }, + }) + expect(deparse.body).toMatchInlineSnapshot(` + "CREATE TABLE table_name ( + id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + inserted_at pg_catalog.timestamptz DEFAULT ( timezone('utc'::text, now()) ) NOT NULL, + updated_at pg_catalog.timestamptz DEFAULT ( timezone('utc'::text, now()) ) NOT NULL, + data jsonb, + name text + );" + `) +}) + +test('formatter', async () => { + const res = await app.inject({ + method: 'POST', + path: '/query/format', + payload: { query: 'SELECT id, name FROM users where user_id = 1234' }, + }) + expect(res.body).toMatchInlineSnapshot(` + "SELECT + id, + name + FROM + users + where + user_id = 1234 + " + `) +}) + +test('very big number', async () => { + const res = await app.inject({ + method: 'POST', + path: '/query', + payload: { + query: `SELECT ${Number.MAX_SAFE_INTEGER + 1}::int8, ARRAY[${ + Number.MIN_SAFE_INTEGER - 1 + }::int8]`, + }, + }) + expect(res.json()).toMatchInlineSnapshot(` + [ + { + "array": [ + "-9007199254740992", + ], + "int8": "9007199254740992", + }, + ] + `) +}) + +// issue: https://github.com/supabase/supabase/issues/27626 +test('return interval as string', async () => { + const res = await app.inject({ + method: 'POST', + path: '/query', + payload: { + query: `SELECT '1 day 1 hour 45 minutes'::interval`, + }, + }) + expect(res.json()).toMatchInlineSnapshot(` + [ + { + "interval": "1 day 01:45:00", + }, + ] + `) +}) + +test('line position error', async () => { + const res = await app.inject({ + method: 'POST', + path: '/query', + payload: { query: 'SELECT *\nFROM pg_class\nWHERE relname = missing_quotes;' }, + }) + expect(res.json()).toMatchInlineSnapshot(` + { + "code": "42703", + "error": "ERROR: 42703: column "missing_quotes" does not exist + LINE 3: WHERE relname = missing_quotes; + ^ + ", + "file": "parse_relation.c", + "formattedError": "ERROR: 42703: column "missing_quotes" does not exist + LINE 3: WHERE relname = missing_quotes; + ^ + ", + "length": 114, + "line": "3589", + "message": "column "missing_quotes" does not exist", + "name": "error", + "position": "40", + "routine": "errorMissingColumn", + "severity": "ERROR", + } + `) +}) + +test('error with additional details', async () => { + // This query will generate an error with details + const res = await app.inject({ + method: 'POST', + path: '/query', + payload: { + query: `DO $$ + DECLARE + my_var int; + BEGIN + -- This will trigger an error with detail, hint, and context + SELECT * INTO STRICT my_var FROM (VALUES (1), (2)) AS t(v); + END $$;`, + }, + }) + + expect(res.json()).toMatchInlineSnapshot(` + { + "code": "P0003", + "error": "ERROR: P0003: query returned more than one row + HINT: Make sure the query returns a single row, or use LIMIT 1. + CONTEXT: PL/pgSQL function inline_code_block line 6 at SQL statement + ", + "file": "pl_exec.c", + "formattedError": "ERROR: P0003: query returned more than one row + HINT: Make sure the query returns a single row, or use LIMIT 1. + CONTEXT: PL/pgSQL function inline_code_block line 6 at SQL statement + ", + "hint": "Make sure the query returns a single row, or use LIMIT 1.", + "length": 216, + "line": "4349", + "message": "query returned more than one row", + "name": "error", + "routine": "exec_stmt_execsql", + "severity": "ERROR", + "where": "PL/pgSQL function inline_code_block line 6 at SQL statement", + } + `) +}) + +test('error with all formatting properties', async () => { + // This query will generate an error with all formatting properties + const res = await app.inject({ + method: 'POST', + path: '/query', + payload: { + query: ` + DO $$ + BEGIN + -- Using EXECUTE to force internal query to appear + EXECUTE 'SELECT * FROM nonexistent_table WHERE id = 1'; + EXCEPTION WHEN OTHERS THEN + -- Re-raise with added context + RAISE EXCEPTION USING + ERRCODE = SQLSTATE, + MESSAGE = SQLERRM, + DETAIL = 'This is additional detail information', + HINT = 'This is a hint for fixing the issue', + SCHEMA = 'public'; + END $$; + `, + }, + }) + + expect(res.json()).toMatchInlineSnapshot(` + { + "code": "42P01", + "detail": "This is additional detail information", + "error": "ERROR: 42P01: relation "nonexistent_table" does not exist + DETAIL: This is additional detail information + HINT: This is a hint for fixing the issue + CONTEXT: PL/pgSQL function inline_code_block line 7 at RAISE + ", + "file": "pl_exec.c", + "formattedError": "ERROR: 42P01: relation "nonexistent_table" does not exist + DETAIL: This is additional detail information + HINT: This is a hint for fixing the issue + CONTEXT: PL/pgSQL function inline_code_block line 7 at RAISE + ", + "hint": "This is a hint for fixing the issue", + "length": 242, + "line": "3859", + "message": "relation "nonexistent_table" does not exist", + "name": "error", + "routine": "exec_stmt_raise", + "schema": "public", + "severity": "ERROR", + "where": "PL/pgSQL function inline_code_block line 7 at RAISE", + } + `) +}) + +test('error with internalQuery property', async () => { + // First create a function that will execute a query internally + await app.inject({ + method: 'POST', + path: '/query', + payload: { + query: ` + CREATE OR REPLACE FUNCTION test_internal_query() RETURNS void AS $$ + BEGIN + -- This query will be the "internal query" when it fails + EXECUTE 'SELECT * FROM nonexistent_table'; + RETURN; + END; + $$ LANGUAGE plpgsql; + `, + }, + }) + + // Now call the function to trigger the error with internalQuery + const res = await app.inject({ + method: 'POST', + path: '/query', + payload: { + query: 'SELECT test_internal_query();', + }, + }) + + expect(res.json()).toMatchInlineSnapshot(` + { + "code": "42P01", + "error": "ERROR: 42P01: relation "nonexistent_table" does not exist + QUERY: SELECT * FROM nonexistent_table + CONTEXT: PL/pgSQL function test_internal_query() line 4 at EXECUTE + ", + "file": "parse_relation.c", + "formattedError": "ERROR: 42P01: relation "nonexistent_table" does not exist + QUERY: SELECT * FROM nonexistent_table + CONTEXT: PL/pgSQL function test_internal_query() line 4 at EXECUTE + ", + "internalPosition": "15", + "internalQuery": "SELECT * FROM nonexistent_table", + "length": 208, + "line": "1381", + "message": "relation "nonexistent_table" does not exist", + "name": "error", + "routine": "parserOpenTable", + "severity": "ERROR", + "where": "PL/pgSQL function test_internal_query() line 4 at EXECUTE", + } + `) +}) + +test('custom application_name', async () => { + const res = await app.inject({ + method: 'POST', + path: '/query', + headers: { + 'x-pg-application-name': 'test', + }, + payload: { + query: 'SHOW application_name;', + }, + }) + + expect(res.json()).toMatchInlineSnapshot(` + [ + { + "application_name": "test", + }, + ] + `) +}) diff --git a/test/server/result-size-limit.ts b/test/server/result-size-limit.ts new file mode 100644 index 00000000..15543d67 --- /dev/null +++ b/test/server/result-size-limit.ts @@ -0,0 +1,140 @@ +import { expect, test, beforeAll, afterAll, describe } from 'vitest' +import { app } from './utils' +import { pgMeta } from '../lib/utils' + +describe('test max-result-size limit', () => { + // Create a table with large data for testing + beforeAll(async () => { + // Create a table with a large text column + await pgMeta.query(` + CREATE TABLE large_data ( + id SERIAL PRIMARY KEY, + data TEXT + ); + `) + await pgMeta.query(` + CREATE TABLE small_data ( + id SERIAL PRIMARY KEY, + data TEXT + ); + `) + + // Insert data that will exceed our limit in tests it's set around ~20MB + await pgMeta.query(` + INSERT INTO large_data (data) + SELECT repeat('x', 1024 * 1024) -- 1MB of data per row + FROM generate_series(1, 50); + `) + await pgMeta.query(` + INSERT INTO small_data (data) + SELECT repeat('x', 10 * 1024) -- 10KB per row + FROM generate_series(1, 50); + `) + }) + + afterAll(async () => { + // Clean up the test table + await pgMeta.query('DROP TABLE large_data;') + await pgMeta.query('DROP TABLE small_data;') + }) + + test('query exceeding result size limit', async () => { + // Set a small maxResultSize (50MB) + const res = await app.inject({ + method: 'POST', + path: '/query', + payload: { query: 'SELECT * FROM large_data;' }, + }) + + // Check that we get the proper error response + expect(res.statusCode).toBe(400) + expect(res.json()).toMatchObject({ + error: expect.stringContaining('Query result size'), + code: 'RESULT_SIZE_EXCEEDED', + resultSize: expect.any(Number), + maxResultSize: 20 * 1024 * 1024, + }) + + // Verify that subsequent queries still work and the server isn't killed + const nextRes = await app.inject({ + method: 'POST', + path: '/query', + payload: { query: 'SELECT * FROM small_data;' }, + }) + + expect(nextRes.statusCode).toBe(200) + // Should have retrieve the 50 rows as expected + expect(nextRes.json()).toHaveLength(50) + }) +}) + +describe('test js parser error max result', () => { + // Create a table with large data for testing + beforeAll(async () => { + // Create a table with a large text column + await pgMeta.query(` + CREATE TABLE very_large_data ( + id SERIAL PRIMARY KEY, + data TEXT + ); + `) + + // Insert data that will exceed our limit in tests it's set around ~20MB + await pgMeta.query(` + INSERT INTO very_large_data (data) + VALUES (repeat('x', 710 * 1024 * 1024)) -- 700+MB string will raise a JS exception at parse time + `) + }) + + afterAll(async () => { + // Clean up the test table + await pgMeta.query('DROP TABLE very_large_data;') + }) + + test( + 'should not kill the server on underlying parser error', + async () => { + // Set a small maxResultSize (50MB) + const res = await app.inject({ + method: 'POST', + path: '/query', + payload: { query: 'SELECT * FROM very_large_data;' }, + }) + + // Check that we get the proper error response from the underlying parser + expect(res.json()).toMatchInlineSnapshot(` + { + "error": "exception received while handling packet: Error: Cannot create a string longer than 0x1fffffe8 characters + ", + "formattedError": "exception received while handling packet: Error: Cannot create a string longer than 0x1fffffe8 characters + ", + "length": 744488975, + "message": "exception received while handling packet: Error: Cannot create a string longer than 0x1fffffe8 characters", + "name": "error", + } + `) + + // Verify that subsequent queries still work and the server isn't killed + const nextRes = await app.inject({ + method: 'POST', + path: '/query', + payload: { query: 'SELECT * FROM todos;' }, + }) + expect(nextRes.json()).toMatchInlineSnapshot(` + [ + { + "details": "Star the repo", + "id": 1, + "user-id": 1, + }, + { + "details": "Watch the releases", + "id": 2, + "user-id": 2, + }, + ] + `) + }, + { timeout: 20000 } + ) +}) diff --git a/test/server/ssl.ts b/test/server/ssl.ts new file mode 100644 index 00000000..5b6cc83b --- /dev/null +++ b/test/server/ssl.ts @@ -0,0 +1,128 @@ +import CryptoJS from 'crypto-js' +import fs from 'node:fs' +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import { expect, test } from 'vitest' +import { app } from './utils' +import { CRYPTO_KEY, DEFAULT_POOL_CONFIG } from '../../src/server/constants' + +// @ts-ignore: Harmless type error on import.meta. +const cwd = path.dirname(fileURLToPath(import.meta.url)) +const sslRootCertPath = path.join(cwd, '../db/server.crt') +const sslRootCert = fs.readFileSync(sslRootCertPath, { encoding: 'utf8' }) + +test('query with no ssl', async () => { + const res = await app.inject({ + method: 'POST', + path: '/query', + headers: { + 'x-connection-encrypted': CryptoJS.AES.encrypt( + 'postgresql://postgres:postgres@localhost:5432/postgres', + CRYPTO_KEY + ).toString(), + }, + payload: { query: 'select 1;' }, + }) + expect(res.json()).toMatchInlineSnapshot(` + [ + { + "?column?": 1, + }, + ] + `) +}) + +test('query with ssl w/o root cert', async () => { + const res = await app.inject({ + method: 'POST', + path: '/query', + headers: { + 'x-connection-encrypted': CryptoJS.AES.encrypt( + 'postgresql://postgres:postgres@localhost:5432/postgres?sslmode=verify-full', + CRYPTO_KEY + ).toString(), + }, + payload: { query: 'select 1;' }, + }) + expect(res.json()?.error).toMatch(/^self[ -]signed certificate$/) +}) + +test('query with ssl with root cert', async () => { + const defaultSsl = DEFAULT_POOL_CONFIG.ssl + DEFAULT_POOL_CONFIG.ssl = { ca: sslRootCert } + + const res = await app.inject({ + method: 'POST', + path: '/query', + headers: { + 'x-connection-encrypted': CryptoJS.AES.encrypt( + `postgresql://postgres:postgres@localhost:5432/postgres?sslmode=verify-full`, + CRYPTO_KEY + ).toString(), + }, + payload: { query: 'select 1;' }, + }) + expect(res.json()).toMatchInlineSnapshot(` + [ + { + "?column?": 1, + }, + ] + `) + + DEFAULT_POOL_CONFIG.ssl = defaultSsl +}) + +test('query with invalid space empty encrypted connection string', async () => { + const res = await app.inject({ + method: 'POST', + path: '/query', + headers: { + 'x-connection-encrypted': CryptoJS.AES.encrypt(` `, CRYPTO_KEY).toString(), + }, + payload: { query: 'select 1;' }, + }) + expect(res.statusCode).toBe(500) + expect(res.json()).toMatchInlineSnapshot(` + { + "error": "failed to get upstream connection details", + } + `) +}) + +test('query with invalid empty encrypted connection string', async () => { + const res = await app.inject({ + method: 'POST', + path: '/query', + headers: { + 'x-connection-encrypted': CryptoJS.AES.encrypt(``, CRYPTO_KEY).toString(), + }, + payload: { query: 'select 1;' }, + }) + expect(res.statusCode).toBe(500) + expect(res.json()).toMatchInlineSnapshot(` + { + "error": "failed to get upstream connection details", + } + `) +}) + +test('query with missing host connection string encrypted connection string', async () => { + const res = await app.inject({ + method: 'POST', + path: '/query', + headers: { + 'x-connection-encrypted': CryptoJS.AES.encrypt( + `postgres://name:password@:5432/postgres?sslmode=prefer`, + CRYPTO_KEY + ).toString(), + }, + payload: { query: 'select 1;' }, + }) + expect(res.statusCode).toBe(500) + expect(res.json()).toMatchInlineSnapshot(` + { + "error": "failed to process upstream connection details", + } + `) +}) diff --git a/test/server/table-privileges.ts b/test/server/table-privileges.ts new file mode 100644 index 00000000..732510ef --- /dev/null +++ b/test/server/table-privileges.ts @@ -0,0 +1,377 @@ +import { expect, test } from 'vitest' +import { PostgresTablePrivileges } from '../../src/lib/types' +import { app } from './utils' + +test('list table privileges', async () => { + const res = await app.inject({ method: 'GET', path: '/table-privileges' }) + expect( + res + .json() + .find(({ schema, name }) => schema === 'public' && name === 'todos') + ).toMatchInlineSnapshot( + { relation_id: expect.any(Number) }, + ` + { + "kind": "table", + "name": "todos", + "privileges": [ + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "INSERT", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "SELECT", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "UPDATE", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "DELETE", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "TRUNCATE", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "REFERENCES", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "TRIGGER", + }, + ], + "relation_id": Any, + "schema": "public", + } + ` + ) +}) + +test('revoke & grant table privileges', async () => { + let res = await app.inject({ method: 'GET', path: '/table-privileges' }) + const { relation_id } = res + .json() + .find(({ schema, name }) => schema === 'public' && name === 'todos')! + + res = await app.inject({ + method: 'DELETE', + path: '/table-privileges', + payload: [ + { + relation_id, + grantee: 'postgres', + privilege_type: 'ALL', + }, + ], + }) + let privs = res.json() + expect(privs.length).toBe(1) + expect(privs[0]).toMatchInlineSnapshot( + { relation_id: expect.any(Number) }, + ` + { + "kind": "table", + "name": "todos", + "privileges": [], + "relation_id": Any, + "schema": "public", + } + ` + ) + + res = await app.inject({ + method: 'POST', + path: '/table-privileges', + payload: [ + { + relation_id, + grantee: 'postgres', + privilege_type: 'ALL', + }, + ], + }) + privs = res.json() + expect(privs.length).toBe(1) + expect(privs[0]).toMatchInlineSnapshot( + { relation_id: expect.any(Number) }, + ` + { + "kind": "table", + "name": "todos", + "privileges": [ + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "TRIGGER", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "REFERENCES", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "TRUNCATE", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "DELETE", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "UPDATE", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "SELECT", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "INSERT", + }, + ], + "relation_id": Any, + "schema": "public", + } + ` + ) +}) + +test('revoke & grant table privileges w/ quoted table name', async () => { + let res = await app.inject({ + method: 'POST', + path: '/query', + payload: { + query: `create role r; create schema "s 1"; create table "s 1"."t 1"();`, + }, + }) + if (res.json().error) { + throw new Error(res.payload) + } + + res = await app.inject({ method: 'GET', path: '/table-privileges' }) + const { relation_id } = res + .json() + .find(({ schema, name }) => schema === 's 1' && name === 't 1')! + + res = await app.inject({ + method: 'POST', + path: '/table-privileges', + payload: [ + { + relation_id, + grantee: 'r', + privilege_type: 'ALL', + }, + ], + }) + let privs = res.json() + expect(privs.length).toBe(1) + expect(privs[0]).toMatchInlineSnapshot( + { relation_id: expect.any(Number) }, + ` + { + "kind": "table", + "name": "t 1", + "privileges": [ + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "TRIGGER", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "REFERENCES", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "TRUNCATE", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "DELETE", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "UPDATE", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "SELECT", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "INSERT", + }, + { + "grantee": "r", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "TRIGGER", + }, + { + "grantee": "r", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "REFERENCES", + }, + { + "grantee": "r", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "TRUNCATE", + }, + { + "grantee": "r", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "DELETE", + }, + { + "grantee": "r", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "UPDATE", + }, + { + "grantee": "r", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "SELECT", + }, + { + "grantee": "r", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "INSERT", + }, + ], + "relation_id": Any, + "schema": "s 1", + } + ` + ) + + res = await app.inject({ + method: 'DELETE', + path: '/table-privileges', + payload: [ + { + relation_id, + grantee: 'r', + privilege_type: 'ALL', + }, + ], + }) + privs = res.json() + expect(privs.length).toBe(1) + expect(privs[0]).toMatchInlineSnapshot( + { relation_id: expect.any(Number) }, + ` + { + "kind": "table", + "name": "t 1", + "privileges": [ + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "TRIGGER", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "REFERENCES", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "TRUNCATE", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "DELETE", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "UPDATE", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "SELECT", + }, + { + "grantee": "postgres", + "grantor": "postgres", + "is_grantable": false, + "privilege_type": "INSERT", + }, + ], + "relation_id": Any, + "schema": "s 1", + } + ` + ) + + res = await app.inject({ + method: 'POST', + path: '/query', + payload: { + query: `drop role r; drop schema "s 1" cascade;`, + }, + }) + if (res.json().error) { + throw new Error(res.payload) + } +}) diff --git a/test/server/typegen.ts b/test/server/typegen.ts new file mode 100644 index 00000000..c0851ef1 --- /dev/null +++ b/test/server/typegen.ts @@ -0,0 +1,2798 @@ +import { expect, test } from 'vitest' +import { app } from './utils' + +test('typegen: typescript', async () => { + const { body } = await app.inject({ method: 'GET', path: '/generators/typescript' }) + expect(body).toMatchInlineSnapshot( + ` + "export type Json = + | string + | number + | boolean + | null + | { [key: string]: Json | undefined } + | Json[] + + export type Database = { + public: { + Tables: { + category: { + Row: { + id: number + name: string + } + Insert: { + id?: number + name: string + } + Update: { + id?: number + name?: string + } + Relationships: [] + } + empty: { + Row: {} + Insert: {} + Update: {} + Relationships: [] + } + foreign_table: { + Row: { + id: number + name: string | null + status: Database["public"]["Enums"]["user_status"] | null + } + Insert: { + id: number + name?: string | null + status?: Database["public"]["Enums"]["user_status"] | null + } + Update: { + id?: number + name?: string | null + status?: Database["public"]["Enums"]["user_status"] | null + } + Relationships: [] + } + memes: { + Row: { + category: number | null + created_at: string + id: number + metadata: Json | null + name: string + status: Database["public"]["Enums"]["meme_status"] | null + } + Insert: { + category?: number | null + created_at: string + id?: number + metadata?: Json | null + name: string + status?: Database["public"]["Enums"]["meme_status"] | null + } + Update: { + category?: number | null + created_at?: string + id?: number + metadata?: Json | null + name?: string + status?: Database["public"]["Enums"]["meme_status"] | null + } + Relationships: [ + { + foreignKeyName: "memes_category_fkey" + columns: ["category"] + referencedRelation: "category" + referencedColumns: ["id"] + }, + ] + } + table_with_other_tables_row_type: { + Row: { + col1: Database["public"]["Tables"]["user_details"]["Row"] | null + col2: Database["public"]["Views"]["a_view"]["Row"] | null + } + Insert: { + col1?: Database["public"]["Tables"]["user_details"]["Row"] | null + col2?: Database["public"]["Views"]["a_view"]["Row"] | null + } + Update: { + col1?: Database["public"]["Tables"]["user_details"]["Row"] | null + col2?: Database["public"]["Views"]["a_view"]["Row"] | null + } + Relationships: [] + } + table_with_primary_key_other_than_id: { + Row: { + name: string | null + other_id: number + } + Insert: { + name?: string | null + other_id?: number + } + Update: { + name?: string | null + other_id?: number + } + Relationships: [] + } + todos: { + Row: { + details: string | null + id: number + "user-id": number + blurb: string | null + blurb_varchar: string | null + details_is_long: boolean | null + details_length: number | null + details_words: string[] | null + } + Insert: { + details?: string | null + id?: number + "user-id": number + } + Update: { + details?: string | null + id?: number + "user-id"?: number + } + Relationships: [ + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + referencedRelation: "a_view" + referencedColumns: ["id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + referencedRelation: "users" + referencedColumns: ["id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + referencedRelation: "users_view" + referencedColumns: ["id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + referencedRelation: "users_view_with_multiple_refs_to_users" + referencedColumns: ["initial_id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + referencedRelation: "users_view_with_multiple_refs_to_users" + referencedColumns: ["second_id"] + }, + ] + } + user_details: { + Row: { + details: string | null + user_id: number + } + Insert: { + details?: string | null + user_id: number + } + Update: { + details?: string | null + user_id?: number + } + Relationships: [ + { + foreignKeyName: "user_details_user_id_fkey" + columns: ["user_id"] + referencedRelation: "a_view" + referencedColumns: ["id"] + }, + { + foreignKeyName: "user_details_user_id_fkey" + columns: ["user_id"] + referencedRelation: "users" + referencedColumns: ["id"] + }, + { + foreignKeyName: "user_details_user_id_fkey" + columns: ["user_id"] + referencedRelation: "users_view" + referencedColumns: ["id"] + }, + { + foreignKeyName: "user_details_user_id_fkey" + columns: ["user_id"] + referencedRelation: "users_view_with_multiple_refs_to_users" + referencedColumns: ["initial_id"] + }, + { + foreignKeyName: "user_details_user_id_fkey" + columns: ["user_id"] + referencedRelation: "users_view_with_multiple_refs_to_users" + referencedColumns: ["second_id"] + }, + ] + } + users: { + Row: { + id: number + name: string | null + status: Database["public"]["Enums"]["user_status"] | null + } + Insert: { + id?: number + name?: string | null + status?: Database["public"]["Enums"]["user_status"] | null + } + Update: { + id?: number + name?: string | null + status?: Database["public"]["Enums"]["user_status"] | null + } + Relationships: [] + } + users_audit: { + Row: { + created_at: string | null + id: number + previous_value: Json | null + user_id: number | null + } + Insert: { + created_at?: string | null + id?: number + previous_value?: Json | null + user_id?: number | null + } + Update: { + created_at?: string | null + id?: number + previous_value?: Json | null + user_id?: number | null + } + Relationships: [] + } + } + Views: { + a_view: { + Row: { + id: number | null + } + Insert: { + id?: number | null + } + Update: { + id?: number | null + } + Relationships: [] + } + todos_matview: { + Row: { + details: string | null + id: number | null + "user-id": number | null + } + Relationships: [ + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + referencedRelation: "a_view" + referencedColumns: ["id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + referencedRelation: "users" + referencedColumns: ["id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + referencedRelation: "users_view" + referencedColumns: ["id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + referencedRelation: "users_view_with_multiple_refs_to_users" + referencedColumns: ["initial_id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + referencedRelation: "users_view_with_multiple_refs_to_users" + referencedColumns: ["second_id"] + }, + ] + } + todos_view: { + Row: { + details: string | null + id: number | null + "user-id": number | null + } + Insert: { + details?: string | null + id?: number | null + "user-id"?: number | null + } + Update: { + details?: string | null + id?: number | null + "user-id"?: number | null + } + Relationships: [ + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + referencedRelation: "a_view" + referencedColumns: ["id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + referencedRelation: "users" + referencedColumns: ["id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + referencedRelation: "users_view" + referencedColumns: ["id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + referencedRelation: "users_view_with_multiple_refs_to_users" + referencedColumns: ["initial_id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + referencedRelation: "users_view_with_multiple_refs_to_users" + referencedColumns: ["second_id"] + }, + ] + } + users_view: { + Row: { + id: number | null + name: string | null + status: Database["public"]["Enums"]["user_status"] | null + } + Insert: { + id?: number | null + name?: string | null + status?: Database["public"]["Enums"]["user_status"] | null + } + Update: { + id?: number | null + name?: string | null + status?: Database["public"]["Enums"]["user_status"] | null + } + Relationships: [] + } + users_view_with_multiple_refs_to_users: { + Row: { + initial_id: number | null + initial_name: string | null + second_id: number | null + second_name: string | null + } + Relationships: [] + } + } + Functions: { + blurb: { + Args: { "": Database["public"]["Tables"]["todos"]["Row"] } + Returns: string + } + blurb_varchar: { + Args: { "": Database["public"]["Tables"]["todos"]["Row"] } + Returns: string + } + details_is_long: { + Args: { "": Database["public"]["Tables"]["todos"]["Row"] } + Returns: boolean + } + details_length: { + Args: { "": Database["public"]["Tables"]["todos"]["Row"] } + Returns: number + } + details_words: { + Args: { "": Database["public"]["Tables"]["todos"]["Row"] } + Returns: string[] + } + function_returning_row: { + Args: Record + Returns: { + id: number + name: string | null + status: Database["public"]["Enums"]["user_status"] | null + } + } + function_returning_set_of_rows: { + Args: Record + Returns: { + id: number + name: string | null + status: Database["public"]["Enums"]["user_status"] | null + }[] + } + function_returning_table: { + Args: Record + Returns: { + id: number + name: string + }[] + } + get_todos_setof_rows: { + Args: + | { todo_row: Database["public"]["Tables"]["todos"]["Row"] } + | { user_row: Database["public"]["Tables"]["users"]["Row"] } + Returns: { + details: string | null + id: number + "user-id": number + }[] + } + get_user_audit_setof_single_row: { + Args: { user_row: Database["public"]["Tables"]["users"]["Row"] } + Returns: { + created_at: string | null + id: number + previous_value: Json | null + user_id: number | null + }[] + } + polymorphic_function: { + Args: { "": boolean } | { "": string } + Returns: undefined + } + postgres_fdw_disconnect: { + Args: { "": string } + Returns: boolean + } + postgres_fdw_disconnect_all: { + Args: Record + Returns: boolean + } + postgres_fdw_get_connections: { + Args: Record + Returns: Record[] + } + postgres_fdw_handler: { + Args: Record + Returns: unknown + } + test_internal_query: { + Args: Record + Returns: undefined + } + } + Enums: { + meme_status: "new" | "old" | "retired" + user_status: "ACTIVE" | "INACTIVE" + } + CompositeTypes: { + composite_type_with_array_attribute: { + my_text_array: string[] | null + } + composite_type_with_record_attribute: { + todo: Database["public"]["Tables"]["todos"]["Row"] | null + } + } + } + } + + type DefaultSchema = Database[Extract] + + export type Tables< + DefaultSchemaTableNameOrOptions extends + | keyof (DefaultSchema["Tables"] & DefaultSchema["Views"]) + | { schema: keyof Database }, + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof Database + } + ? keyof (Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] & + Database[DefaultSchemaTableNameOrOptions["schema"]]["Views"]) + : never = never, + > = DefaultSchemaTableNameOrOptions extends { schema: keyof Database } + ? (Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] & + Database[DefaultSchemaTableNameOrOptions["schema"]]["Views"])[TableName] extends { + Row: infer R + } + ? R + : never + : DefaultSchemaTableNameOrOptions extends keyof (DefaultSchema["Tables"] & + DefaultSchema["Views"]) + ? (DefaultSchema["Tables"] & + DefaultSchema["Views"])[DefaultSchemaTableNameOrOptions] extends { + Row: infer R + } + ? R + : never + : never + + export type TablesInsert< + DefaultSchemaTableNameOrOptions extends + | keyof DefaultSchema["Tables"] + | { schema: keyof Database }, + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof Database + } + ? keyof Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] + : never = never, + > = DefaultSchemaTableNameOrOptions extends { schema: keyof Database } + ? Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"][TableName] extends { + Insert: infer I + } + ? I + : never + : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema["Tables"] + ? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends { + Insert: infer I + } + ? I + : never + : never + + export type TablesUpdate< + DefaultSchemaTableNameOrOptions extends + | keyof DefaultSchema["Tables"] + | { schema: keyof Database }, + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof Database + } + ? keyof Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] + : never = never, + > = DefaultSchemaTableNameOrOptions extends { schema: keyof Database } + ? Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"][TableName] extends { + Update: infer U + } + ? U + : never + : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema["Tables"] + ? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends { + Update: infer U + } + ? U + : never + : never + + export type Enums< + DefaultSchemaEnumNameOrOptions extends + | keyof DefaultSchema["Enums"] + | { schema: keyof Database }, + EnumName extends DefaultSchemaEnumNameOrOptions extends { + schema: keyof Database + } + ? keyof Database[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"] + : never = never, + > = DefaultSchemaEnumNameOrOptions extends { schema: keyof Database } + ? Database[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"][EnumName] + : DefaultSchemaEnumNameOrOptions extends keyof DefaultSchema["Enums"] + ? DefaultSchema["Enums"][DefaultSchemaEnumNameOrOptions] + : never + + export type CompositeTypes< + PublicCompositeTypeNameOrOptions extends + | keyof DefaultSchema["CompositeTypes"] + | { schema: keyof Database }, + CompositeTypeName extends PublicCompositeTypeNameOrOptions extends { + schema: keyof Database + } + ? keyof Database[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"] + : never = never, + > = PublicCompositeTypeNameOrOptions extends { schema: keyof Database } + ? Database[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"][CompositeTypeName] + : PublicCompositeTypeNameOrOptions extends keyof DefaultSchema["CompositeTypes"] + ? DefaultSchema["CompositeTypes"][PublicCompositeTypeNameOrOptions] + : never + + export const Constants = { + public: { + Enums: { + meme_status: ["new", "old", "retired"], + user_status: ["ACTIVE", "INACTIVE"], + }, + }, + } as const + " + ` + ) +}) + +test('typegen w/ one-to-one relationships', async () => { + const { body } = await app.inject({ + method: 'GET', + path: '/generators/typescript', + query: { detect_one_to_one_relationships: 'true' }, + }) + expect(body).toMatchInlineSnapshot( + ` + "export type Json = + | string + | number + | boolean + | null + | { [key: string]: Json | undefined } + | Json[] + + export type Database = { + public: { + Tables: { + category: { + Row: { + id: number + name: string + } + Insert: { + id?: number + name: string + } + Update: { + id?: number + name?: string + } + Relationships: [] + } + empty: { + Row: {} + Insert: {} + Update: {} + Relationships: [] + } + foreign_table: { + Row: { + id: number + name: string | null + status: Database["public"]["Enums"]["user_status"] | null + } + Insert: { + id: number + name?: string | null + status?: Database["public"]["Enums"]["user_status"] | null + } + Update: { + id?: number + name?: string | null + status?: Database["public"]["Enums"]["user_status"] | null + } + Relationships: [] + } + memes: { + Row: { + category: number | null + created_at: string + id: number + metadata: Json | null + name: string + status: Database["public"]["Enums"]["meme_status"] | null + } + Insert: { + category?: number | null + created_at: string + id?: number + metadata?: Json | null + name: string + status?: Database["public"]["Enums"]["meme_status"] | null + } + Update: { + category?: number | null + created_at?: string + id?: number + metadata?: Json | null + name?: string + status?: Database["public"]["Enums"]["meme_status"] | null + } + Relationships: [ + { + foreignKeyName: "memes_category_fkey" + columns: ["category"] + isOneToOne: false + referencedRelation: "category" + referencedColumns: ["id"] + }, + ] + } + table_with_other_tables_row_type: { + Row: { + col1: Database["public"]["Tables"]["user_details"]["Row"] | null + col2: Database["public"]["Views"]["a_view"]["Row"] | null + } + Insert: { + col1?: Database["public"]["Tables"]["user_details"]["Row"] | null + col2?: Database["public"]["Views"]["a_view"]["Row"] | null + } + Update: { + col1?: Database["public"]["Tables"]["user_details"]["Row"] | null + col2?: Database["public"]["Views"]["a_view"]["Row"] | null + } + Relationships: [] + } + table_with_primary_key_other_than_id: { + Row: { + name: string | null + other_id: number + } + Insert: { + name?: string | null + other_id?: number + } + Update: { + name?: string | null + other_id?: number + } + Relationships: [] + } + todos: { + Row: { + details: string | null + id: number + "user-id": number + blurb: string | null + blurb_varchar: string | null + details_is_long: boolean | null + details_length: number | null + details_words: string[] | null + } + Insert: { + details?: string | null + id?: number + "user-id": number + } + Update: { + details?: string | null + id?: number + "user-id"?: number + } + Relationships: [ + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + isOneToOne: false + referencedRelation: "a_view" + referencedColumns: ["id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + isOneToOne: false + referencedRelation: "users" + referencedColumns: ["id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + isOneToOne: false + referencedRelation: "users_view" + referencedColumns: ["id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + isOneToOne: false + referencedRelation: "users_view_with_multiple_refs_to_users" + referencedColumns: ["initial_id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + isOneToOne: false + referencedRelation: "users_view_with_multiple_refs_to_users" + referencedColumns: ["second_id"] + }, + ] + } + user_details: { + Row: { + details: string | null + user_id: number + } + Insert: { + details?: string | null + user_id: number + } + Update: { + details?: string | null + user_id?: number + } + Relationships: [ + { + foreignKeyName: "user_details_user_id_fkey" + columns: ["user_id"] + isOneToOne: true + referencedRelation: "a_view" + referencedColumns: ["id"] + }, + { + foreignKeyName: "user_details_user_id_fkey" + columns: ["user_id"] + isOneToOne: true + referencedRelation: "users" + referencedColumns: ["id"] + }, + { + foreignKeyName: "user_details_user_id_fkey" + columns: ["user_id"] + isOneToOne: true + referencedRelation: "users_view" + referencedColumns: ["id"] + }, + { + foreignKeyName: "user_details_user_id_fkey" + columns: ["user_id"] + isOneToOne: true + referencedRelation: "users_view_with_multiple_refs_to_users" + referencedColumns: ["initial_id"] + }, + { + foreignKeyName: "user_details_user_id_fkey" + columns: ["user_id"] + isOneToOne: true + referencedRelation: "users_view_with_multiple_refs_to_users" + referencedColumns: ["second_id"] + }, + ] + } + users: { + Row: { + id: number + name: string | null + status: Database["public"]["Enums"]["user_status"] | null + } + Insert: { + id?: number + name?: string | null + status?: Database["public"]["Enums"]["user_status"] | null + } + Update: { + id?: number + name?: string | null + status?: Database["public"]["Enums"]["user_status"] | null + } + Relationships: [] + } + users_audit: { + Row: { + created_at: string | null + id: number + previous_value: Json | null + user_id: number | null + } + Insert: { + created_at?: string | null + id?: number + previous_value?: Json | null + user_id?: number | null + } + Update: { + created_at?: string | null + id?: number + previous_value?: Json | null + user_id?: number | null + } + Relationships: [] + } + } + Views: { + a_view: { + Row: { + id: number | null + } + Insert: { + id?: number | null + } + Update: { + id?: number | null + } + Relationships: [] + } + todos_matview: { + Row: { + details: string | null + id: number | null + "user-id": number | null + } + Relationships: [ + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + isOneToOne: false + referencedRelation: "a_view" + referencedColumns: ["id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + isOneToOne: false + referencedRelation: "users" + referencedColumns: ["id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + isOneToOne: false + referencedRelation: "users_view" + referencedColumns: ["id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + isOneToOne: false + referencedRelation: "users_view_with_multiple_refs_to_users" + referencedColumns: ["initial_id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + isOneToOne: false + referencedRelation: "users_view_with_multiple_refs_to_users" + referencedColumns: ["second_id"] + }, + ] + } + todos_view: { + Row: { + details: string | null + id: number | null + "user-id": number | null + } + Insert: { + details?: string | null + id?: number | null + "user-id"?: number | null + } + Update: { + details?: string | null + id?: number | null + "user-id"?: number | null + } + Relationships: [ + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + isOneToOne: false + referencedRelation: "a_view" + referencedColumns: ["id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + isOneToOne: false + referencedRelation: "users" + referencedColumns: ["id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + isOneToOne: false + referencedRelation: "users_view" + referencedColumns: ["id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + isOneToOne: false + referencedRelation: "users_view_with_multiple_refs_to_users" + referencedColumns: ["initial_id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + isOneToOne: false + referencedRelation: "users_view_with_multiple_refs_to_users" + referencedColumns: ["second_id"] + }, + ] + } + users_view: { + Row: { + id: number | null + name: string | null + status: Database["public"]["Enums"]["user_status"] | null + } + Insert: { + id?: number | null + name?: string | null + status?: Database["public"]["Enums"]["user_status"] | null + } + Update: { + id?: number | null + name?: string | null + status?: Database["public"]["Enums"]["user_status"] | null + } + Relationships: [] + } + users_view_with_multiple_refs_to_users: { + Row: { + initial_id: number | null + initial_name: string | null + second_id: number | null + second_name: string | null + } + Relationships: [] + } + } + Functions: { + blurb: { + Args: { "": Database["public"]["Tables"]["todos"]["Row"] } + Returns: string + } + blurb_varchar: { + Args: { "": Database["public"]["Tables"]["todos"]["Row"] } + Returns: string + } + details_is_long: { + Args: { "": Database["public"]["Tables"]["todos"]["Row"] } + Returns: boolean + } + details_length: { + Args: { "": Database["public"]["Tables"]["todos"]["Row"] } + Returns: number + } + details_words: { + Args: { "": Database["public"]["Tables"]["todos"]["Row"] } + Returns: string[] + } + function_returning_row: { + Args: Record + Returns: { + id: number + name: string | null + status: Database["public"]["Enums"]["user_status"] | null + } + } + function_returning_set_of_rows: { + Args: Record + Returns: { + id: number + name: string | null + status: Database["public"]["Enums"]["user_status"] | null + }[] + } + function_returning_table: { + Args: Record + Returns: { + id: number + name: string + }[] + } + get_todos_setof_rows: { + Args: + | { todo_row: Database["public"]["Tables"]["todos"]["Row"] } + | { user_row: Database["public"]["Tables"]["users"]["Row"] } + Returns: { + details: string | null + id: number + "user-id": number + }[] + } + get_user_audit_setof_single_row: { + Args: { user_row: Database["public"]["Tables"]["users"]["Row"] } + Returns: { + created_at: string | null + id: number + previous_value: Json | null + user_id: number | null + }[] + } + polymorphic_function: { + Args: { "": boolean } | { "": string } + Returns: undefined + } + postgres_fdw_disconnect: { + Args: { "": string } + Returns: boolean + } + postgres_fdw_disconnect_all: { + Args: Record + Returns: boolean + } + postgres_fdw_get_connections: { + Args: Record + Returns: Record[] + } + postgres_fdw_handler: { + Args: Record + Returns: unknown + } + test_internal_query: { + Args: Record + Returns: undefined + } + } + Enums: { + meme_status: "new" | "old" | "retired" + user_status: "ACTIVE" | "INACTIVE" + } + CompositeTypes: { + composite_type_with_array_attribute: { + my_text_array: string[] | null + } + composite_type_with_record_attribute: { + todo: Database["public"]["Tables"]["todos"]["Row"] | null + } + } + } + } + + type DefaultSchema = Database[Extract] + + export type Tables< + DefaultSchemaTableNameOrOptions extends + | keyof (DefaultSchema["Tables"] & DefaultSchema["Views"]) + | { schema: keyof Database }, + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof Database + } + ? keyof (Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] & + Database[DefaultSchemaTableNameOrOptions["schema"]]["Views"]) + : never = never, + > = DefaultSchemaTableNameOrOptions extends { schema: keyof Database } + ? (Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] & + Database[DefaultSchemaTableNameOrOptions["schema"]]["Views"])[TableName] extends { + Row: infer R + } + ? R + : never + : DefaultSchemaTableNameOrOptions extends keyof (DefaultSchema["Tables"] & + DefaultSchema["Views"]) + ? (DefaultSchema["Tables"] & + DefaultSchema["Views"])[DefaultSchemaTableNameOrOptions] extends { + Row: infer R + } + ? R + : never + : never + + export type TablesInsert< + DefaultSchemaTableNameOrOptions extends + | keyof DefaultSchema["Tables"] + | { schema: keyof Database }, + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof Database + } + ? keyof Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] + : never = never, + > = DefaultSchemaTableNameOrOptions extends { schema: keyof Database } + ? Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"][TableName] extends { + Insert: infer I + } + ? I + : never + : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema["Tables"] + ? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends { + Insert: infer I + } + ? I + : never + : never + + export type TablesUpdate< + DefaultSchemaTableNameOrOptions extends + | keyof DefaultSchema["Tables"] + | { schema: keyof Database }, + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof Database + } + ? keyof Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] + : never = never, + > = DefaultSchemaTableNameOrOptions extends { schema: keyof Database } + ? Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"][TableName] extends { + Update: infer U + } + ? U + : never + : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema["Tables"] + ? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends { + Update: infer U + } + ? U + : never + : never + + export type Enums< + DefaultSchemaEnumNameOrOptions extends + | keyof DefaultSchema["Enums"] + | { schema: keyof Database }, + EnumName extends DefaultSchemaEnumNameOrOptions extends { + schema: keyof Database + } + ? keyof Database[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"] + : never = never, + > = DefaultSchemaEnumNameOrOptions extends { schema: keyof Database } + ? Database[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"][EnumName] + : DefaultSchemaEnumNameOrOptions extends keyof DefaultSchema["Enums"] + ? DefaultSchema["Enums"][DefaultSchemaEnumNameOrOptions] + : never + + export type CompositeTypes< + PublicCompositeTypeNameOrOptions extends + | keyof DefaultSchema["CompositeTypes"] + | { schema: keyof Database }, + CompositeTypeName extends PublicCompositeTypeNameOrOptions extends { + schema: keyof Database + } + ? keyof Database[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"] + : never = never, + > = PublicCompositeTypeNameOrOptions extends { schema: keyof Database } + ? Database[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"][CompositeTypeName] + : PublicCompositeTypeNameOrOptions extends keyof DefaultSchema["CompositeTypes"] + ? DefaultSchema["CompositeTypes"][PublicCompositeTypeNameOrOptions] + : never + + export const Constants = { + public: { + Enums: { + meme_status: ["new", "old", "retired"], + user_status: ["ACTIVE", "INACTIVE"], + }, + }, + } as const + " + ` + ) +}) + +test('typegen: typescript w/ one-to-one relationships', async () => { + const { body } = await app.inject({ + method: 'GET', + path: '/generators/typescript', + query: { detect_one_to_one_relationships: 'true' }, + }) + expect(body).toMatchInlineSnapshot( + ` + "export type Json = + | string + | number + | boolean + | null + | { [key: string]: Json | undefined } + | Json[] + + export type Database = { + public: { + Tables: { + category: { + Row: { + id: number + name: string + } + Insert: { + id?: number + name: string + } + Update: { + id?: number + name?: string + } + Relationships: [] + } + empty: { + Row: {} + Insert: {} + Update: {} + Relationships: [] + } + foreign_table: { + Row: { + id: number + name: string | null + status: Database["public"]["Enums"]["user_status"] | null + } + Insert: { + id: number + name?: string | null + status?: Database["public"]["Enums"]["user_status"] | null + } + Update: { + id?: number + name?: string | null + status?: Database["public"]["Enums"]["user_status"] | null + } + Relationships: [] + } + memes: { + Row: { + category: number | null + created_at: string + id: number + metadata: Json | null + name: string + status: Database["public"]["Enums"]["meme_status"] | null + } + Insert: { + category?: number | null + created_at: string + id?: number + metadata?: Json | null + name: string + status?: Database["public"]["Enums"]["meme_status"] | null + } + Update: { + category?: number | null + created_at?: string + id?: number + metadata?: Json | null + name?: string + status?: Database["public"]["Enums"]["meme_status"] | null + } + Relationships: [ + { + foreignKeyName: "memes_category_fkey" + columns: ["category"] + isOneToOne: false + referencedRelation: "category" + referencedColumns: ["id"] + }, + ] + } + table_with_other_tables_row_type: { + Row: { + col1: Database["public"]["Tables"]["user_details"]["Row"] | null + col2: Database["public"]["Views"]["a_view"]["Row"] | null + } + Insert: { + col1?: Database["public"]["Tables"]["user_details"]["Row"] | null + col2?: Database["public"]["Views"]["a_view"]["Row"] | null + } + Update: { + col1?: Database["public"]["Tables"]["user_details"]["Row"] | null + col2?: Database["public"]["Views"]["a_view"]["Row"] | null + } + Relationships: [] + } + table_with_primary_key_other_than_id: { + Row: { + name: string | null + other_id: number + } + Insert: { + name?: string | null + other_id?: number + } + Update: { + name?: string | null + other_id?: number + } + Relationships: [] + } + todos: { + Row: { + details: string | null + id: number + "user-id": number + blurb: string | null + blurb_varchar: string | null + details_is_long: boolean | null + details_length: number | null + details_words: string[] | null + } + Insert: { + details?: string | null + id?: number + "user-id": number + } + Update: { + details?: string | null + id?: number + "user-id"?: number + } + Relationships: [ + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + isOneToOne: false + referencedRelation: "a_view" + referencedColumns: ["id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + isOneToOne: false + referencedRelation: "users" + referencedColumns: ["id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + isOneToOne: false + referencedRelation: "users_view" + referencedColumns: ["id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + isOneToOne: false + referencedRelation: "users_view_with_multiple_refs_to_users" + referencedColumns: ["initial_id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + isOneToOne: false + referencedRelation: "users_view_with_multiple_refs_to_users" + referencedColumns: ["second_id"] + }, + ] + } + user_details: { + Row: { + details: string | null + user_id: number + } + Insert: { + details?: string | null + user_id: number + } + Update: { + details?: string | null + user_id?: number + } + Relationships: [ + { + foreignKeyName: "user_details_user_id_fkey" + columns: ["user_id"] + isOneToOne: true + referencedRelation: "a_view" + referencedColumns: ["id"] + }, + { + foreignKeyName: "user_details_user_id_fkey" + columns: ["user_id"] + isOneToOne: true + referencedRelation: "users" + referencedColumns: ["id"] + }, + { + foreignKeyName: "user_details_user_id_fkey" + columns: ["user_id"] + isOneToOne: true + referencedRelation: "users_view" + referencedColumns: ["id"] + }, + { + foreignKeyName: "user_details_user_id_fkey" + columns: ["user_id"] + isOneToOne: true + referencedRelation: "users_view_with_multiple_refs_to_users" + referencedColumns: ["initial_id"] + }, + { + foreignKeyName: "user_details_user_id_fkey" + columns: ["user_id"] + isOneToOne: true + referencedRelation: "users_view_with_multiple_refs_to_users" + referencedColumns: ["second_id"] + }, + ] + } + users: { + Row: { + id: number + name: string | null + status: Database["public"]["Enums"]["user_status"] | null + } + Insert: { + id?: number + name?: string | null + status?: Database["public"]["Enums"]["user_status"] | null + } + Update: { + id?: number + name?: string | null + status?: Database["public"]["Enums"]["user_status"] | null + } + Relationships: [] + } + users_audit: { + Row: { + created_at: string | null + id: number + previous_value: Json | null + user_id: number | null + } + Insert: { + created_at?: string | null + id?: number + previous_value?: Json | null + user_id?: number | null + } + Update: { + created_at?: string | null + id?: number + previous_value?: Json | null + user_id?: number | null + } + Relationships: [] + } + } + Views: { + a_view: { + Row: { + id: number | null + } + Insert: { + id?: number | null + } + Update: { + id?: number | null + } + Relationships: [] + } + todos_matview: { + Row: { + details: string | null + id: number | null + "user-id": number | null + } + Relationships: [ + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + isOneToOne: false + referencedRelation: "a_view" + referencedColumns: ["id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + isOneToOne: false + referencedRelation: "users" + referencedColumns: ["id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + isOneToOne: false + referencedRelation: "users_view" + referencedColumns: ["id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + isOneToOne: false + referencedRelation: "users_view_with_multiple_refs_to_users" + referencedColumns: ["initial_id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + isOneToOne: false + referencedRelation: "users_view_with_multiple_refs_to_users" + referencedColumns: ["second_id"] + }, + ] + } + todos_view: { + Row: { + details: string | null + id: number | null + "user-id": number | null + } + Insert: { + details?: string | null + id?: number | null + "user-id"?: number | null + } + Update: { + details?: string | null + id?: number | null + "user-id"?: number | null + } + Relationships: [ + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + isOneToOne: false + referencedRelation: "a_view" + referencedColumns: ["id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + isOneToOne: false + referencedRelation: "users" + referencedColumns: ["id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + isOneToOne: false + referencedRelation: "users_view" + referencedColumns: ["id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + isOneToOne: false + referencedRelation: "users_view_with_multiple_refs_to_users" + referencedColumns: ["initial_id"] + }, + { + foreignKeyName: "todos_user-id_fkey" + columns: ["user-id"] + isOneToOne: false + referencedRelation: "users_view_with_multiple_refs_to_users" + referencedColumns: ["second_id"] + }, + ] + } + users_view: { + Row: { + id: number | null + name: string | null + status: Database["public"]["Enums"]["user_status"] | null + } + Insert: { + id?: number | null + name?: string | null + status?: Database["public"]["Enums"]["user_status"] | null + } + Update: { + id?: number | null + name?: string | null + status?: Database["public"]["Enums"]["user_status"] | null + } + Relationships: [] + } + users_view_with_multiple_refs_to_users: { + Row: { + initial_id: number | null + initial_name: string | null + second_id: number | null + second_name: string | null + } + Relationships: [] + } + } + Functions: { + blurb: { + Args: { "": Database["public"]["Tables"]["todos"]["Row"] } + Returns: string + } + blurb_varchar: { + Args: { "": Database["public"]["Tables"]["todos"]["Row"] } + Returns: string + } + details_is_long: { + Args: { "": Database["public"]["Tables"]["todos"]["Row"] } + Returns: boolean + } + details_length: { + Args: { "": Database["public"]["Tables"]["todos"]["Row"] } + Returns: number + } + details_words: { + Args: { "": Database["public"]["Tables"]["todos"]["Row"] } + Returns: string[] + } + function_returning_row: { + Args: Record + Returns: { + id: number + name: string | null + status: Database["public"]["Enums"]["user_status"] | null + } + } + function_returning_set_of_rows: { + Args: Record + Returns: { + id: number + name: string | null + status: Database["public"]["Enums"]["user_status"] | null + }[] + } + function_returning_table: { + Args: Record + Returns: { + id: number + name: string + }[] + } + get_todos_setof_rows: { + Args: + | { todo_row: Database["public"]["Tables"]["todos"]["Row"] } + | { user_row: Database["public"]["Tables"]["users"]["Row"] } + Returns: { + details: string | null + id: number + "user-id": number + }[] + } + get_user_audit_setof_single_row: { + Args: { user_row: Database["public"]["Tables"]["users"]["Row"] } + Returns: { + created_at: string | null + id: number + previous_value: Json | null + user_id: number | null + }[] + } + polymorphic_function: { + Args: { "": boolean } | { "": string } + Returns: undefined + } + postgres_fdw_disconnect: { + Args: { "": string } + Returns: boolean + } + postgres_fdw_disconnect_all: { + Args: Record + Returns: boolean + } + postgres_fdw_get_connections: { + Args: Record + Returns: Record[] + } + postgres_fdw_handler: { + Args: Record + Returns: unknown + } + test_internal_query: { + Args: Record + Returns: undefined + } + } + Enums: { + meme_status: "new" | "old" | "retired" + user_status: "ACTIVE" | "INACTIVE" + } + CompositeTypes: { + composite_type_with_array_attribute: { + my_text_array: string[] | null + } + composite_type_with_record_attribute: { + todo: Database["public"]["Tables"]["todos"]["Row"] | null + } + } + } + } + + type DefaultSchema = Database[Extract] + + export type Tables< + DefaultSchemaTableNameOrOptions extends + | keyof (DefaultSchema["Tables"] & DefaultSchema["Views"]) + | { schema: keyof Database }, + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof Database + } + ? keyof (Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] & + Database[DefaultSchemaTableNameOrOptions["schema"]]["Views"]) + : never = never, + > = DefaultSchemaTableNameOrOptions extends { schema: keyof Database } + ? (Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] & + Database[DefaultSchemaTableNameOrOptions["schema"]]["Views"])[TableName] extends { + Row: infer R + } + ? R + : never + : DefaultSchemaTableNameOrOptions extends keyof (DefaultSchema["Tables"] & + DefaultSchema["Views"]) + ? (DefaultSchema["Tables"] & + DefaultSchema["Views"])[DefaultSchemaTableNameOrOptions] extends { + Row: infer R + } + ? R + : never + : never + + export type TablesInsert< + DefaultSchemaTableNameOrOptions extends + | keyof DefaultSchema["Tables"] + | { schema: keyof Database }, + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof Database + } + ? keyof Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] + : never = never, + > = DefaultSchemaTableNameOrOptions extends { schema: keyof Database } + ? Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"][TableName] extends { + Insert: infer I + } + ? I + : never + : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema["Tables"] + ? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends { + Insert: infer I + } + ? I + : never + : never + + export type TablesUpdate< + DefaultSchemaTableNameOrOptions extends + | keyof DefaultSchema["Tables"] + | { schema: keyof Database }, + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof Database + } + ? keyof Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] + : never = never, + > = DefaultSchemaTableNameOrOptions extends { schema: keyof Database } + ? Database[DefaultSchemaTableNameOrOptions["schema"]]["Tables"][TableName] extends { + Update: infer U + } + ? U + : never + : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema["Tables"] + ? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends { + Update: infer U + } + ? U + : never + : never + + export type Enums< + DefaultSchemaEnumNameOrOptions extends + | keyof DefaultSchema["Enums"] + | { schema: keyof Database }, + EnumName extends DefaultSchemaEnumNameOrOptions extends { + schema: keyof Database + } + ? keyof Database[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"] + : never = never, + > = DefaultSchemaEnumNameOrOptions extends { schema: keyof Database } + ? Database[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"][EnumName] + : DefaultSchemaEnumNameOrOptions extends keyof DefaultSchema["Enums"] + ? DefaultSchema["Enums"][DefaultSchemaEnumNameOrOptions] + : never + + export type CompositeTypes< + PublicCompositeTypeNameOrOptions extends + | keyof DefaultSchema["CompositeTypes"] + | { schema: keyof Database }, + CompositeTypeName extends PublicCompositeTypeNameOrOptions extends { + schema: keyof Database + } + ? keyof Database[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"] + : never = never, + > = PublicCompositeTypeNameOrOptions extends { schema: keyof Database } + ? Database[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"][CompositeTypeName] + : PublicCompositeTypeNameOrOptions extends keyof DefaultSchema["CompositeTypes"] + ? DefaultSchema["CompositeTypes"][PublicCompositeTypeNameOrOptions] + : never + + export const Constants = { + public: { + Enums: { + meme_status: ["new", "old", "retired"], + user_status: ["ACTIVE", "INACTIVE"], + }, + }, + } as const + " + ` + ) +}) + +test('typegen: go', async () => { + const { body } = await app.inject({ method: 'GET', path: '/generators/go' }) + expect(body).toMatchInlineSnapshot(` + "package database + +type PublicUsersSelect struct { + Id int64 \`json:"id"\` + Name *string \`json:"name"\` + Status *string \`json:"status"\` +} + +type PublicUsersInsert struct { + Id *int64 \`json:"id"\` + Name *string \`json:"name"\` + Status *string \`json:"status"\` +} + +type PublicUsersUpdate struct { + Id *int64 \`json:"id"\` + Name *string \`json:"name"\` + Status *string \`json:"status"\` +} + +type PublicTodosSelect struct { + Details *string \`json:"details"\` + Id int64 \`json:"id"\` + UserId int64 \`json:"user-id"\` +} + +type PublicTodosInsert struct { + Details *string \`json:"details"\` + Id *int64 \`json:"id"\` + UserId int64 \`json:"user-id"\` +} + +type PublicTodosUpdate struct { + Details *string \`json:"details"\` + Id *int64 \`json:"id"\` + UserId *int64 \`json:"user-id"\` +} + +type PublicUsersAuditSelect struct { + CreatedAt *string \`json:"created_at"\` + Id int64 \`json:"id"\` + PreviousValue interface{} \`json:"previous_value"\` + UserId *int64 \`json:"user_id"\` +} + +type PublicUsersAuditInsert struct { + CreatedAt *string \`json:"created_at"\` + Id *int64 \`json:"id"\` + PreviousValue interface{} \`json:"previous_value"\` + UserId *int64 \`json:"user_id"\` +} + +type PublicUsersAuditUpdate struct { + CreatedAt *string \`json:"created_at"\` + Id *int64 \`json:"id"\` + PreviousValue interface{} \`json:"previous_value"\` + UserId *int64 \`json:"user_id"\` +} + +type PublicUserDetailsSelect struct { + Details *string \`json:"details"\` + UserId int64 \`json:"user_id"\` +} + +type PublicUserDetailsInsert struct { + Details *string \`json:"details"\` + UserId int64 \`json:"user_id"\` +} + +type PublicUserDetailsUpdate struct { + Details *string \`json:"details"\` + UserId *int64 \`json:"user_id"\` +} + +type PublicEmptySelect struct { + +} + +type PublicEmptyInsert struct { + +} + +type PublicEmptyUpdate struct { + +} + +type PublicTableWithOtherTablesRowTypeSelect struct { + Col1 interface{} \`json:"col1"\` + Col2 interface{} \`json:"col2"\` +} + +type PublicTableWithOtherTablesRowTypeInsert struct { + Col1 interface{} \`json:"col1"\` + Col2 interface{} \`json:"col2"\` +} + +type PublicTableWithOtherTablesRowTypeUpdate struct { + Col1 interface{} \`json:"col1"\` + Col2 interface{} \`json:"col2"\` +} + +type PublicTableWithPrimaryKeyOtherThanIdSelect struct { + Name *string \`json:"name"\` + OtherId int64 \`json:"other_id"\` +} + +type PublicTableWithPrimaryKeyOtherThanIdInsert struct { + Name *string \`json:"name"\` + OtherId *int64 \`json:"other_id"\` +} + +type PublicTableWithPrimaryKeyOtherThanIdUpdate struct { + Name *string \`json:"name"\` + OtherId *int64 \`json:"other_id"\` +} + +type PublicCategorySelect struct { + Id int32 \`json:"id"\` + Name string \`json:"name"\` +} + +type PublicCategoryInsert struct { + Id *int32 \`json:"id"\` + Name string \`json:"name"\` +} + +type PublicCategoryUpdate struct { + Id *int32 \`json:"id"\` + Name *string \`json:"name"\` +} + +type PublicMemesSelect struct { + Category *int32 \`json:"category"\` + CreatedAt string \`json:"created_at"\` + Id int32 \`json:"id"\` + Metadata interface{} \`json:"metadata"\` + Name string \`json:"name"\` + Status *string \`json:"status"\` +} + +type PublicMemesInsert struct { + Category *int32 \`json:"category"\` + CreatedAt string \`json:"created_at"\` + Id *int32 \`json:"id"\` + Metadata interface{} \`json:"metadata"\` + Name string \`json:"name"\` + Status *string \`json:"status"\` +} + +type PublicMemesUpdate struct { + Category *int32 \`json:"category"\` + CreatedAt *string \`json:"created_at"\` + Id *int32 \`json:"id"\` + Metadata interface{} \`json:"metadata"\` + Name *string \`json:"name"\` + Status *string \`json:"status"\` +} + +type PublicTodosViewSelect struct { + Details *string \`json:"details"\` + Id *int64 \`json:"id"\` + UserId *int64 \`json:"user-id"\` +} + +type PublicUsersViewSelect struct { + Id *int64 \`json:"id"\` + Name *string \`json:"name"\` + Status *string \`json:"status"\` +} + +type PublicAViewSelect struct { + Id *int64 \`json:"id"\` +} + +type PublicUsersViewWithMultipleRefsToUsersSelect struct { + InitialId *int64 \`json:"initial_id"\` + InitialName *string \`json:"initial_name"\` + SecondId *int64 \`json:"second_id"\` + SecondName *string \`json:"second_name"\` +} + +type PublicTodosMatviewSelect struct { + Details *string \`json:"details"\` + Id *int64 \`json:"id"\` + UserId *int64 \`json:"user-id"\` +} + +type PublicCompositeTypeWithArrayAttribute struct { + MyTextArray interface{} \`json:"my_text_array"\` +} + +type PublicCompositeTypeWithRecordAttribute struct { + Todo interface{} \`json:"todo"\` +}" + `) +}) + +test('typegen: swift', async () => { + const { body } = await app.inject({ method: 'GET', path: '/generators/swift' }) + expect(body).toMatchInlineSnapshot(` + "import Foundation + import Supabase + + internal enum PublicSchema { + internal enum MemeStatus: String, Codable, Hashable, Sendable { + case new = "new" + case old = "old" + case retired = "retired" + } + internal enum UserStatus: String, Codable, Hashable, Sendable { + case active = "ACTIVE" + case inactive = "INACTIVE" + } + internal struct CategorySelect: Codable, Hashable, Sendable { + internal let id: Int32 + internal let name: String + internal enum CodingKeys: String, CodingKey { + case id = "id" + case name = "name" + } + } + internal struct CategoryInsert: Codable, Hashable, Sendable { + internal let id: Int32? + internal let name: String + internal enum CodingKeys: String, CodingKey { + case id = "id" + case name = "name" + } + } + internal struct CategoryUpdate: Codable, Hashable, Sendable { + internal let id: Int32? + internal let name: String? + internal enum CodingKeys: String, CodingKey { + case id = "id" + case name = "name" + } + } + internal struct EmptySelect: Codable, Hashable, Sendable { + } + internal struct EmptyInsert: Codable, Hashable, Sendable { + } + internal struct EmptyUpdate: Codable, Hashable, Sendable { + } + internal struct ForeignTableSelect: Codable, Hashable, Sendable { + internal let id: Int64 + internal let name: String? + internal let status: UserStatus? + internal enum CodingKeys: String, CodingKey { + case id = "id" + case name = "name" + case status = "status" + } + } + internal struct ForeignTableInsert: Codable, Hashable, Sendable { + internal let id: Int64 + internal let name: String? + internal let status: UserStatus? + internal enum CodingKeys: String, CodingKey { + case id = "id" + case name = "name" + case status = "status" + } + } + internal struct ForeignTableUpdate: Codable, Hashable, Sendable { + internal let id: Int64? + internal let name: String? + internal let status: UserStatus? + internal enum CodingKeys: String, CodingKey { + case id = "id" + case name = "name" + case status = "status" + } + } + internal struct MemesSelect: Codable, Hashable, Sendable { + internal let category: Int32? + internal let createdAt: String + internal let id: Int32 + internal let metadata: AnyJSON? + internal let name: String + internal let status: MemeStatus? + internal enum CodingKeys: String, CodingKey { + case category = "category" + case createdAt = "created_at" + case id = "id" + case metadata = "metadata" + case name = "name" + case status = "status" + } + } + internal struct MemesInsert: Codable, Hashable, Sendable { + internal let category: Int32? + internal let createdAt: String + internal let id: Int32? + internal let metadata: AnyJSON? + internal let name: String + internal let status: MemeStatus? + internal enum CodingKeys: String, CodingKey { + case category = "category" + case createdAt = "created_at" + case id = "id" + case metadata = "metadata" + case name = "name" + case status = "status" + } + } + internal struct MemesUpdate: Codable, Hashable, Sendable { + internal let category: Int32? + internal let createdAt: String? + internal let id: Int32? + internal let metadata: AnyJSON? + internal let name: String? + internal let status: MemeStatus? + internal enum CodingKeys: String, CodingKey { + case category = "category" + case createdAt = "created_at" + case id = "id" + case metadata = "metadata" + case name = "name" + case status = "status" + } + } + internal struct TableWithOtherTablesRowTypeSelect: Codable, Hashable, Sendable { + internal let col1: UserDetailsSelect? + internal let col2: AViewSelect? + internal enum CodingKeys: String, CodingKey { + case col1 = "col1" + case col2 = "col2" + } + } + internal struct TableWithOtherTablesRowTypeInsert: Codable, Hashable, Sendable { + internal let col1: UserDetailsSelect? + internal let col2: AViewSelect? + internal enum CodingKeys: String, CodingKey { + case col1 = "col1" + case col2 = "col2" + } + } + internal struct TableWithOtherTablesRowTypeUpdate: Codable, Hashable, Sendable { + internal let col1: UserDetailsSelect? + internal let col2: AViewSelect? + internal enum CodingKeys: String, CodingKey { + case col1 = "col1" + case col2 = "col2" + } + } + internal struct TableWithPrimaryKeyOtherThanIdSelect: Codable, Hashable, Sendable, Identifiable { + internal var id: Int64 { otherId } + internal let name: String? + internal let otherId: Int64 + internal enum CodingKeys: String, CodingKey { + case name = "name" + case otherId = "other_id" + } + } + internal struct TableWithPrimaryKeyOtherThanIdInsert: Codable, Hashable, Sendable, Identifiable { + internal var id: Int64? { otherId } + internal let name: String? + internal let otherId: Int64? + internal enum CodingKeys: String, CodingKey { + case name = "name" + case otherId = "other_id" + } + } + internal struct TableWithPrimaryKeyOtherThanIdUpdate: Codable, Hashable, Sendable, Identifiable { + internal var id: Int64? { otherId } + internal let name: String? + internal let otherId: Int64? + internal enum CodingKeys: String, CodingKey { + case name = "name" + case otherId = "other_id" + } + } + internal struct TodosSelect: Codable, Hashable, Sendable, Identifiable { + internal let details: String? + internal let id: Int64 + internal let userId: Int64 + internal enum CodingKeys: String, CodingKey { + case details = "details" + case id = "id" + case userId = "user-id" + } + } + internal struct TodosInsert: Codable, Hashable, Sendable, Identifiable { + internal let details: String? + internal let id: Int64? + internal let userId: Int64 + internal enum CodingKeys: String, CodingKey { + case details = "details" + case id = "id" + case userId = "user-id" + } + } + internal struct TodosUpdate: Codable, Hashable, Sendable, Identifiable { + internal let details: String? + internal let id: Int64? + internal let userId: Int64? + internal enum CodingKeys: String, CodingKey { + case details = "details" + case id = "id" + case userId = "user-id" + } + } + internal struct UserDetailsSelect: Codable, Hashable, Sendable { + internal let details: String? + internal let userId: Int64 + internal enum CodingKeys: String, CodingKey { + case details = "details" + case userId = "user_id" + } + } + internal struct UserDetailsInsert: Codable, Hashable, Sendable { + internal let details: String? + internal let userId: Int64 + internal enum CodingKeys: String, CodingKey { + case details = "details" + case userId = "user_id" + } + } + internal struct UserDetailsUpdate: Codable, Hashable, Sendable { + internal let details: String? + internal let userId: Int64? + internal enum CodingKeys: String, CodingKey { + case details = "details" + case userId = "user_id" + } + } + internal struct UsersSelect: Codable, Hashable, Sendable, Identifiable { + internal let id: Int64 + internal let name: String? + internal let status: UserStatus? + internal enum CodingKeys: String, CodingKey { + case id = "id" + case name = "name" + case status = "status" + } + } + internal struct UsersInsert: Codable, Hashable, Sendable, Identifiable { + internal let id: Int64? + internal let name: String? + internal let status: UserStatus? + internal enum CodingKeys: String, CodingKey { + case id = "id" + case name = "name" + case status = "status" + } + } + internal struct UsersUpdate: Codable, Hashable, Sendable, Identifiable { + internal let id: Int64? + internal let name: String? + internal let status: UserStatus? + internal enum CodingKeys: String, CodingKey { + case id = "id" + case name = "name" + case status = "status" + } + } + internal struct UsersAuditSelect: Codable, Hashable, Sendable, Identifiable { + internal let createdAt: String? + internal let id: Int64 + internal let previousValue: AnyJSON? + internal let userId: Int64? + internal enum CodingKeys: String, CodingKey { + case createdAt = "created_at" + case id = "id" + case previousValue = "previous_value" + case userId = "user_id" + } + } + internal struct UsersAuditInsert: Codable, Hashable, Sendable, Identifiable { + internal let createdAt: String? + internal let id: Int64? + internal let previousValue: AnyJSON? + internal let userId: Int64? + internal enum CodingKeys: String, CodingKey { + case createdAt = "created_at" + case id = "id" + case previousValue = "previous_value" + case userId = "user_id" + } + } + internal struct UsersAuditUpdate: Codable, Hashable, Sendable, Identifiable { + internal let createdAt: String? + internal let id: Int64? + internal let previousValue: AnyJSON? + internal let userId: Int64? + internal enum CodingKeys: String, CodingKey { + case createdAt = "created_at" + case id = "id" + case previousValue = "previous_value" + case userId = "user_id" + } + } + internal struct AViewSelect: Codable, Hashable, Sendable { + internal let id: Int64? + internal enum CodingKeys: String, CodingKey { + case id = "id" + } + } + internal struct TodosMatviewSelect: Codable, Hashable, Sendable { + internal let details: String? + internal let id: Int64? + internal let userId: Int64? + internal enum CodingKeys: String, CodingKey { + case details = "details" + case id = "id" + case userId = "user-id" + } + } + internal struct TodosViewSelect: Codable, Hashable, Sendable { + internal let details: String? + internal let id: Int64? + internal let userId: Int64? + internal enum CodingKeys: String, CodingKey { + case details = "details" + case id = "id" + case userId = "user-id" + } + } + internal struct UsersViewSelect: Codable, Hashable, Sendable { + internal let id: Int64? + internal let name: String? + internal let status: UserStatus? + internal enum CodingKeys: String, CodingKey { + case id = "id" + case name = "name" + case status = "status" + } + } + internal struct UsersViewWithMultipleRefsToUsersSelect: Codable, Hashable, Sendable { + internal let initialId: Int64? + internal let initialName: String? + internal let secondId: Int64? + internal let secondName: String? + internal enum CodingKeys: String, CodingKey { + case initialId = "initial_id" + case initialName = "initial_name" + case secondId = "second_id" + case secondName = "second_name" + } + } + internal struct CompositeTypeWithArrayAttribute: Codable, Hashable, Sendable { + internal let MyTextArray: AnyJSON + internal enum CodingKeys: String, CodingKey { + case MyTextArray = "my_text_array" + } + } + internal struct CompositeTypeWithRecordAttribute: Codable, Hashable, Sendable { + internal let Todo: TodosSelect + internal enum CodingKeys: String, CodingKey { + case Todo = "todo" + } + } + }" + `) +}) + +test('typegen: swift w/ public access control', async () => { + const { body } = await app.inject({ + method: 'GET', + path: '/generators/swift', + query: { access_control: 'public' }, + }) + expect(body).toMatchInlineSnapshot(` + "import Foundation + import Supabase + + public enum PublicSchema { + public enum MemeStatus: String, Codable, Hashable, Sendable { + case new = "new" + case old = "old" + case retired = "retired" + } + public enum UserStatus: String, Codable, Hashable, Sendable { + case active = "ACTIVE" + case inactive = "INACTIVE" + } + public struct CategorySelect: Codable, Hashable, Sendable { + public let id: Int32 + public let name: String + public enum CodingKeys: String, CodingKey { + case id = "id" + case name = "name" + } + } + public struct CategoryInsert: Codable, Hashable, Sendable { + public let id: Int32? + public let name: String + public enum CodingKeys: String, CodingKey { + case id = "id" + case name = "name" + } + } + public struct CategoryUpdate: Codable, Hashable, Sendable { + public let id: Int32? + public let name: String? + public enum CodingKeys: String, CodingKey { + case id = "id" + case name = "name" + } + } + public struct EmptySelect: Codable, Hashable, Sendable { + } + public struct EmptyInsert: Codable, Hashable, Sendable { + } + public struct EmptyUpdate: Codable, Hashable, Sendable { + } + public struct ForeignTableSelect: Codable, Hashable, Sendable { + public let id: Int64 + public let name: String? + public let status: UserStatus? + public enum CodingKeys: String, CodingKey { + case id = "id" + case name = "name" + case status = "status" + } + } + public struct ForeignTableInsert: Codable, Hashable, Sendable { + public let id: Int64 + public let name: String? + public let status: UserStatus? + public enum CodingKeys: String, CodingKey { + case id = "id" + case name = "name" + case status = "status" + } + } + public struct ForeignTableUpdate: Codable, Hashable, Sendable { + public let id: Int64? + public let name: String? + public let status: UserStatus? + public enum CodingKeys: String, CodingKey { + case id = "id" + case name = "name" + case status = "status" + } + } + public struct MemesSelect: Codable, Hashable, Sendable { + public let category: Int32? + public let createdAt: String + public let id: Int32 + public let metadata: AnyJSON? + public let name: String + public let status: MemeStatus? + public enum CodingKeys: String, CodingKey { + case category = "category" + case createdAt = "created_at" + case id = "id" + case metadata = "metadata" + case name = "name" + case status = "status" + } + } + public struct MemesInsert: Codable, Hashable, Sendable { + public let category: Int32? + public let createdAt: String + public let id: Int32? + public let metadata: AnyJSON? + public let name: String + public let status: MemeStatus? + public enum CodingKeys: String, CodingKey { + case category = "category" + case createdAt = "created_at" + case id = "id" + case metadata = "metadata" + case name = "name" + case status = "status" + } + } + public struct MemesUpdate: Codable, Hashable, Sendable { + public let category: Int32? + public let createdAt: String? + public let id: Int32? + public let metadata: AnyJSON? + public let name: String? + public let status: MemeStatus? + public enum CodingKeys: String, CodingKey { + case category = "category" + case createdAt = "created_at" + case id = "id" + case metadata = "metadata" + case name = "name" + case status = "status" + } + } + public struct TableWithOtherTablesRowTypeSelect: Codable, Hashable, Sendable { + public let col1: UserDetailsSelect? + public let col2: AViewSelect? + public enum CodingKeys: String, CodingKey { + case col1 = "col1" + case col2 = "col2" + } + } + public struct TableWithOtherTablesRowTypeInsert: Codable, Hashable, Sendable { + public let col1: UserDetailsSelect? + public let col2: AViewSelect? + public enum CodingKeys: String, CodingKey { + case col1 = "col1" + case col2 = "col2" + } + } + public struct TableWithOtherTablesRowTypeUpdate: Codable, Hashable, Sendable { + public let col1: UserDetailsSelect? + public let col2: AViewSelect? + public enum CodingKeys: String, CodingKey { + case col1 = "col1" + case col2 = "col2" + } + } + public struct TableWithPrimaryKeyOtherThanIdSelect: Codable, Hashable, Sendable, Identifiable { + public var id: Int64 { otherId } + public let name: String? + public let otherId: Int64 + public enum CodingKeys: String, CodingKey { + case name = "name" + case otherId = "other_id" + } + } + public struct TableWithPrimaryKeyOtherThanIdInsert: Codable, Hashable, Sendable, Identifiable { + public var id: Int64? { otherId } + public let name: String? + public let otherId: Int64? + public enum CodingKeys: String, CodingKey { + case name = "name" + case otherId = "other_id" + } + } + public struct TableWithPrimaryKeyOtherThanIdUpdate: Codable, Hashable, Sendable, Identifiable { + public var id: Int64? { otherId } + public let name: String? + public let otherId: Int64? + public enum CodingKeys: String, CodingKey { + case name = "name" + case otherId = "other_id" + } + } + public struct TodosSelect: Codable, Hashable, Sendable, Identifiable { + public let details: String? + public let id: Int64 + public let userId: Int64 + public enum CodingKeys: String, CodingKey { + case details = "details" + case id = "id" + case userId = "user-id" + } + } + public struct TodosInsert: Codable, Hashable, Sendable, Identifiable { + public let details: String? + public let id: Int64? + public let userId: Int64 + public enum CodingKeys: String, CodingKey { + case details = "details" + case id = "id" + case userId = "user-id" + } + } + public struct TodosUpdate: Codable, Hashable, Sendable, Identifiable { + public let details: String? + public let id: Int64? + public let userId: Int64? + public enum CodingKeys: String, CodingKey { + case details = "details" + case id = "id" + case userId = "user-id" + } + } + public struct UserDetailsSelect: Codable, Hashable, Sendable { + public let details: String? + public let userId: Int64 + public enum CodingKeys: String, CodingKey { + case details = "details" + case userId = "user_id" + } + } + public struct UserDetailsInsert: Codable, Hashable, Sendable { + public let details: String? + public let userId: Int64 + public enum CodingKeys: String, CodingKey { + case details = "details" + case userId = "user_id" + } + } + public struct UserDetailsUpdate: Codable, Hashable, Sendable { + public let details: String? + public let userId: Int64? + public enum CodingKeys: String, CodingKey { + case details = "details" + case userId = "user_id" + } + } + public struct UsersSelect: Codable, Hashable, Sendable, Identifiable { + public let id: Int64 + public let name: String? + public let status: UserStatus? + public enum CodingKeys: String, CodingKey { + case id = "id" + case name = "name" + case status = "status" + } + } + public struct UsersInsert: Codable, Hashable, Sendable, Identifiable { + public let id: Int64? + public let name: String? + public let status: UserStatus? + public enum CodingKeys: String, CodingKey { + case id = "id" + case name = "name" + case status = "status" + } + } + public struct UsersUpdate: Codable, Hashable, Sendable, Identifiable { + public let id: Int64? + public let name: String? + public let status: UserStatus? + public enum CodingKeys: String, CodingKey { + case id = "id" + case name = "name" + case status = "status" + } + } + public struct UsersAuditSelect: Codable, Hashable, Sendable, Identifiable { + public let createdAt: String? + public let id: Int64 + public let previousValue: AnyJSON? + public let userId: Int64? + public enum CodingKeys: String, CodingKey { + case createdAt = "created_at" + case id = "id" + case previousValue = "previous_value" + case userId = "user_id" + } + } + public struct UsersAuditInsert: Codable, Hashable, Sendable, Identifiable { + public let createdAt: String? + public let id: Int64? + public let previousValue: AnyJSON? + public let userId: Int64? + public enum CodingKeys: String, CodingKey { + case createdAt = "created_at" + case id = "id" + case previousValue = "previous_value" + case userId = "user_id" + } + } + public struct UsersAuditUpdate: Codable, Hashable, Sendable, Identifiable { + public let createdAt: String? + public let id: Int64? + public let previousValue: AnyJSON? + public let userId: Int64? + public enum CodingKeys: String, CodingKey { + case createdAt = "created_at" + case id = "id" + case previousValue = "previous_value" + case userId = "user_id" + } + } + public struct AViewSelect: Codable, Hashable, Sendable { + public let id: Int64? + public enum CodingKeys: String, CodingKey { + case id = "id" + } + } + public struct TodosMatviewSelect: Codable, Hashable, Sendable { + public let details: String? + public let id: Int64? + public let userId: Int64? + public enum CodingKeys: String, CodingKey { + case details = "details" + case id = "id" + case userId = "user-id" + } + } + public struct TodosViewSelect: Codable, Hashable, Sendable { + public let details: String? + public let id: Int64? + public let userId: Int64? + public enum CodingKeys: String, CodingKey { + case details = "details" + case id = "id" + case userId = "user-id" + } + } + public struct UsersViewSelect: Codable, Hashable, Sendable { + public let id: Int64? + public let name: String? + public let status: UserStatus? + public enum CodingKeys: String, CodingKey { + case id = "id" + case name = "name" + case status = "status" + } + } + public struct UsersViewWithMultipleRefsToUsersSelect: Codable, Hashable, Sendable { + public let initialId: Int64? + public let initialName: String? + public let secondId: Int64? + public let secondName: String? + public enum CodingKeys: String, CodingKey { + case initialId = "initial_id" + case initialName = "initial_name" + case secondId = "second_id" + case secondName = "second_name" + } + } + public struct CompositeTypeWithArrayAttribute: Codable, Hashable, Sendable { + public let MyTextArray: AnyJSON + public enum CodingKeys: String, CodingKey { + case MyTextArray = "my_text_array" + } + } + public struct CompositeTypeWithRecordAttribute: Codable, Hashable, Sendable { + public let Todo: TodosSelect + public enum CodingKeys: String, CodingKey { + case Todo = "todo" + } + } + }" + `) +}) diff --git a/test/server/utils.ts b/test/server/utils.ts new file mode 100644 index 00000000..0222fcf3 --- /dev/null +++ b/test/server/utils.ts @@ -0,0 +1,3 @@ +import { build as buildApp } from '../../src/server/app' + +export const app = buildApp() diff --git a/tsconfig.module.json b/tsconfig.jest.json similarity index 52% rename from tsconfig.module.json rename to tsconfig.jest.json index d424e626..f4c451fd 100644 --- a/tsconfig.module.json +++ b/tsconfig.jest.json @@ -1,7 +1,6 @@ { "extends": "./tsconfig", "compilerOptions": { - "module": "ES2015", - "outDir": "dist/module" + "rootDir": "." } } diff --git a/tsconfig.json b/tsconfig.json index 21407433..24a8d4ca 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,20 +1,21 @@ { - "include": ["src/lib"], + "include": ["src"], "compilerOptions": { + "incremental": true, "declaration": true, "declarationMap": true, - "module": "CommonJS", - "outDir": "dist/main", - "rootDir": "src/lib", + "module": "NodeNext", + "outDir": "dist", + "rootDir": "src", "sourceMap": true, - "target": "ES2015", + "target": "esnext", "strict": true, "esModuleInterop": true, - "moduleResolution": "Node", + "moduleResolution": "NodeNext", "resolveJsonModule": true, - + "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "stripInternal": true } diff --git a/tsconfig.server.json b/tsconfig.server.json deleted file mode 100644 index 750cda7e..00000000 --- a/tsconfig.server.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "include": ["src"], - "compilerOptions": { - "declaration": true, - "declarationMap": true, - "module": "CommonJS", - "outDir": "bin", - "sourceMap": true, - "target": "ES2015", - - "strict": true, - - "esModuleInterop": true, - "moduleResolution": "Node", - "resolveJsonModule": true, - - "forceConsistentCasingInFileNames": true, - "stripInternal": true - } -} diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 00000000..460baf6e --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,13 @@ +/// +import { defineConfig } from 'vitest/config' + +export default defineConfig({ + test: { + coverage: { + reporter: ['lcov'], + }, + maxConcurrency: 1, + // https://github.com/vitest-dev/vitest/issues/317#issuecomment-1542319622 + pool: 'forks', + }, +})