diff --git a/.github/ISSUE_TEMPLATE/security_issue.yml b/.github/ISSUE_TEMPLATE/security_issue.yml index 247073102..fa86d9ddb 100644 --- a/.github/ISSUE_TEMPLATE/security_issue.yml +++ b/.github/ISSUE_TEMPLATE/security_issue.yml @@ -11,6 +11,10 @@ body: value: | ## ❗ IMPORTANT: DO NOT SHARE VULNERABILITY DETAILS HERE + ## Do not report any upstream dependency issues / scan results by any tools. + + It will be closed immediately without explanation, unless you have a PoC to prove that the upstream issue affects Uptime Kuma. + ### ⚠️ Report a Security Vulnerability **If you have discovered a security vulnerability, please report it securely using the GitHub Security Advisory.** diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index e351aa2e2..407d97b18 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,63 +1,34 @@ -## ❗ Important Announcements +_ℹ️ To keep reviews fast and effective, please make sure you’ve [read our pull request guidelines](https://github.com/louislam/uptime-kuma/blob/master/CONTRIBUTING.md#can-i-create-a-pull-request-for-uptime-kuma)_ -
Click here for more details: -

+## 📝 Summary of changes done and why they are done -**⚠️ Please Note: We do not accept all types of pull requests, and we want to ensure we don’t waste your time. Before submitting, make sure you have read our pull request guidelines: [Pull Request Rules](https://github.com/louislam/uptime-kuma/blob/master/CONTRIBUTING.md#can-i-create-a-pull-request-for-uptime-kuma)** + -### 🚫 Please Avoid Unnecessary Pinging of Maintainers -We kindly ask you to refrain from pinging maintainers unless absolutely necessary. Pings are for critical/urgent pull requests that require immediate attention. +## 📋 Related issues -

-
- -## 📋 Overview - - - -- **What problem does this pull request address?** - - Please provide a detailed explanation here. -- **What features or functionality does this pull request introduce or enhance?** - - Please provide a detailed explanation here. - - - -- Relates to #issue-number -- Resolves #issue-number - -## 🛠️ Type of change - - - -- [ ] 🐛 Bugfix (a non-breaking change that resolves an issue) -- [ ] ✨ New feature (a non-breaking change that adds new functionality) -- [ ] ⚠️ Breaking change (a fix or feature that alters existing functionality in a way that could cause issues) -- [ ] 🎨 User Interface (UI) updates -- [ ] 📄 New Documentation (addition of new documentation) -- [ ] 📄 Documentation Update (modification of existing documentation) -- [ ] 📄 Documentation Update Required (the change requires updates to related documentation) -- [ ] 🔧 Other (please specify): - - Provide additional details here. + +- Relates to #issue-number +- Resolves #issue-number ## 📄 Checklist - +
+Please follow this checklist to avoid unnecessary back and forth (click to expand) +- [ ] ⚠️ If there are Breaking change (a fix or feature that alters existing functionality in a way that could cause issues) I have called them out - [ ] 🔍 My code adheres to the style guidelines of this project. - [ ] 🦿 I have indicated where (if any) I used an LLM for the contributions - [ ] ✅ I ran ESLint and other code linters for modified files. +- [ ] ⚠️ My changes generate no new warnings. - [ ] 🛠️ I have reviewed and tested my code. - [ ] 📝 I have commented my code, especially in hard-to-understand areas (e.g., using JSDoc for methods). -- [ ] ⚠️ My changes generate no new warnings. - [ ] 🤖 My code needed automated testing. I have added them (this is an optional task). - [ ] 📄 Documentation updates are included (if applicable). - [ ] 🔒 I have considered potential security impacts and mitigated risks. - [ ] 🧰 Dependency updates are listed and explained. -- [ ] 📚 I have read and understood the [Pull Request guidelines](https://github.com/louislam/uptime-kuma/blob/master/CONTRIBUTING.md#recommended-pull-request-guideline). + +
## 📷 Screenshots or Visual Changes @@ -66,7 +37,6 @@ If this pull request introduces visual changes, please provide the following det If not, remove this section. Please upload the image directly here by pasting it or dragging and dropping. -Avoid using external image services as the image will be uploaded automatically. --> - **UI Modifications**: Highlight any changes made to the user interface. @@ -78,3 +48,12 @@ Avoid using external image services as the image will be uploaded automatically. | `DOWN` | ![Before](image-link) | ![After](image-link) | | Certificate-expiry | ![Before](image-link) | ![After](image-link) | | Testing | ![Before](image-link) | ![After](image-link) | + + diff --git a/.github/workflows/auto-test.yml b/.github/workflows/auto-test.yml index 46fe5d23f..f0dfdfa55 100644 --- a/.github/workflows/auto-test.yml +++ b/.github/workflows/auto-test.yml @@ -15,7 +15,7 @@ on: jobs: auto-test: - needs: [ check-linters ] + needs: [ e2e-test ] runs-on: ${{ matrix.os }} timeout-minutes: 15 @@ -33,6 +33,13 @@ jobs: - run: git config --global core.autocrlf false # Mainly for Windows - uses: actions/checkout@v4 + - name: Cache/Restore node_modules + uses: actions/cache@v4 + id: node-modules-cache + with: + path: node_modules + key: node-modules-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }} + - name: Use Node.js ${{ matrix.node }} uses: actions/setup-node@v6 with: @@ -46,7 +53,7 @@ jobs: # As a lot of dev dependencies are not supported on ARMv7, we have to test it separately and just test if `npm ci --production` works armv7-simple-test: - needs: [ ] + needs: [ e2e-test ] runs-on: ${{ matrix.os }} timeout-minutes: 15 if: ${{ github.repository == 'louislam/uptime-kuma' }} @@ -60,11 +67,18 @@ jobs: - run: git config --global core.autocrlf false # Mainly for Windows - uses: actions/checkout@v4 + - name: Cache/Restore node_modules + uses: actions/cache@v4 + id: node-modules-cache + with: + path: node_modules + key: node-modules-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }} + - name: Use Node.js ${{ matrix.node }} uses: actions/setup-node@v6 with: node-version: ${{ matrix.node }} - - run: npm ci --production + - run: npm install --production check-linters: runs-on: ubuntu-latest @@ -73,6 +87,13 @@ jobs: - run: git config --global core.autocrlf false # Mainly for Windows - uses: actions/checkout@v4 + - name: Cache/Restore node_modules + uses: actions/cache@v4 + id: node-modules-cache + with: + path: node_modules + key: node-modules-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }} + - name: Use Node.js 20 uses: actions/setup-node@v6 with: @@ -81,17 +102,29 @@ jobs: - run: npm run lint:prod e2e-test: - needs: [ ] - runs-on: ubuntu-24.04-arm + needs: [ check-linters ] + runs-on: ARM64 + env: + PLAYWRIGHT_VERSION: ~1.39.0 steps: - run: git config --global core.autocrlf false # Mainly for Windows - uses: actions/checkout@v4 - - name: Use Node.js 20 + - name: Cache/Restore node_modules + uses: actions/cache@v4 + id: node-modules-cache + with: + path: node_modules + key: node-modules-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }} + + - name: Setup Node.js uses: actions/setup-node@v6 with: - node-version: 20 + node-version: 22 - run: npm install - - run: npx playwright install + + - name: Install Playwright ${{ env.PLAYWRIGHT_VERSION }} + run: npx playwright@${{ env.PLAYWRIGHT_VERSION }} install + - run: npm run build - run: npm run test-e2e diff --git a/.github/workflows/close-incorrect-issue.yml b/.github/workflows/close-incorrect-issue.yml index 9d4616931..f618cd7c2 100644 --- a/.github/workflows/close-incorrect-issue.yml +++ b/.github/workflows/close-incorrect-issue.yml @@ -20,6 +20,5 @@ jobs: uses: actions/setup-node@v6 with: node-version: ${{ matrix.node-version }} - cache: 'npm' - run: npm ci - run: node extra/close-incorrect-issue.js ${{ secrets.GITHUB_TOKEN }} ${{ github.event.issue.number }} ${{ github.event.issue.user.login }} diff --git a/db/knex_migrations/2025-09-02-0000-add-domain-expiry.js b/db/knex_migrations/2025-09-02-0000-add-domain-expiry.js new file mode 100644 index 000000000..ede2e1889 --- /dev/null +++ b/db/knex_migrations/2025-09-02-0000-add-domain-expiry.js @@ -0,0 +1,21 @@ +exports.up = function (knex) { + return knex.schema + .alterTable("monitor", function (table) { + table.boolean("domain_expiry_notification").defaultTo(1); + }) + .createTable("domain_expiry", (table) => { + table.increments("id"); + table.datetime("last_check"); + table.text("domain").unique().notNullable(); + table.datetime("expiry"); + table.integer("last_expiry_notification_sent").defaultTo(null); + }); +}; + +exports.down = function (knex) { + return knex.schema + .alterTable("monitor", function (table) { + table.boolean("domain_expiry_notification").alter(); + }) + .dropTable("domain_expiry"); +}; diff --git a/db/knex_migrations/2025-12-22-0121-optimize-important-indexes.js b/db/knex_migrations/2025-12-22-0121-optimize-important-indexes.js new file mode 100644 index 000000000..4208f9511 --- /dev/null +++ b/db/knex_migrations/2025-12-22-0121-optimize-important-indexes.js @@ -0,0 +1,37 @@ +exports.up = async function (knex) { + const isSQLite = knex.client.dialect === "sqlite3"; + + if (isSQLite) { + // For SQLite: Use partial indexes with WHERE important = 1 + // Drop existing indexes using IF EXISTS + await knex.raw("DROP INDEX IF EXISTS monitor_important_time_index"); + await knex.raw("DROP INDEX IF EXISTS heartbeat_important_index"); + + // Create partial indexes with predicate + await knex.schema.alterTable("heartbeat", function (table) { + table.index([ "monitor_id", "time" ], "monitor_important_time_index", { + predicate: knex.whereRaw("important = 1") + }); + table.index([ "important" ], "heartbeat_important_index", { + predicate: knex.whereRaw("important = 1") + }); + }); + } + // For MariaDB/MySQL: No changes (partial indexes not supported) +}; + +exports.down = async function (knex) { + const isSQLite = knex.client.dialect === "sqlite3"; + + if (isSQLite) { + // Restore original indexes + await knex.raw("DROP INDEX IF EXISTS monitor_important_time_index"); + await knex.raw("DROP INDEX IF EXISTS heartbeat_important_index"); + + await knex.schema.alterTable("heartbeat", function (table) { + table.index([ "monitor_id", "important", "time" ], "monitor_important_time_index"); + table.index([ "important" ]); + }); + } + // For MariaDB/MySQL: No changes +}; diff --git a/extra/beta/update-version.js b/extra/beta/update-version.js index 4af645e0e..be0286e3c 100644 --- a/extra/beta/update-version.js +++ b/extra/beta/update-version.js @@ -23,7 +23,18 @@ if (! exists) { // Also update package-lock.json const npm = /^win/.test(process.platform) ? "npm.cmd" : "npm"; - childProcess.spawnSync(npm, [ "install" ]); + const resultVersion = childProcess.spawnSync(npm, [ "--no-git-tag-version", "version", version ], { shell: true }); + if (resultVersion.error) { + console.error(resultVersion.error); + console.error("error npm version!"); + process.exit(1); + } + const resultInstall = childProcess.spawnSync(npm, [ "install" ], { shell: true }); + if (resultInstall.error) { + console.error(resultInstall.error); + console.error("error update package-lock!"); + process.exit(1); + } commit(version); } else { diff --git a/package-lock.json b/package-lock.json index a1c94ee78..1df648a9c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "uptime-kuma", - "version": "2.0.2", + "version": "2.1.0-beta.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "uptime-kuma", - "version": "2.0.2", + "version": "2.1.0-beta.0", "license": "MIT", "dependencies": { "@grpc/grpc-js": "~1.8.22", @@ -60,6 +60,7 @@ "nanoid": "~3.3.4", "net-snmp": "^3.11.2", "node-cloudflared-tunnel": "~1.0.9", + "node-fetch-cache": "^5.1.0", "node-radius-utils": "~1.2.0", "nodemailer": "~6.9.13", "nostr-tools": "^2.10.4", @@ -85,6 +86,7 @@ "tar": "~6.2.1", "tcp-ping": "~0.1.1", "thirty-two": "~1.0.2", + "tldts": "^7.0.19", "tough-cookie": "~4.1.3", "web-push": "^3.6.7", "ws": "^8.13.0" @@ -98,6 +100,7 @@ "@playwright/test": "~1.39.0", "@popperjs/core": "~2.10.2", "@testcontainers/hivemq": "^10.13.1", + "@testcontainers/postgresql": "^11.9.0", "@testcontainers/rabbitmq": "^10.13.2", "@types/bootstrap": "~5.1.9", "@types/node": "^20.8.6", @@ -351,49 +354,49 @@ } }, "node_modules/@aws-sdk/client-cognito-identity": { - "version": "3.913.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.913.0.tgz", - "integrity": "sha512-TdEwasoXnLIb90z7NL1vLbEprzY0vdRqZH97ubIUDo8EaJ6WrJ35Um5g0rcnWKR6C+P9lKKI4mVv2BI2EwY94Q==", + "version": "3.956.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.956.0.tgz", + "integrity": "sha512-aFRUb4BY0iAACVFnLdreULiO5ox1jds5TovncPlUogN5TjVA04i+hmfShj9l5Ho1sFa1WKc35tngiRmpQIJSJg==", "license": "Apache-2.0", "optional": true, "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.911.0", - "@aws-sdk/credential-provider-node": "3.913.0", - "@aws-sdk/middleware-host-header": "3.910.0", - "@aws-sdk/middleware-logger": "3.910.0", - "@aws-sdk/middleware-recursion-detection": "3.910.0", - "@aws-sdk/middleware-user-agent": "3.911.0", - "@aws-sdk/region-config-resolver": "3.910.0", - "@aws-sdk/types": "3.910.0", - "@aws-sdk/util-endpoints": "3.910.0", - "@aws-sdk/util-user-agent-browser": "3.910.0", - "@aws-sdk/util-user-agent-node": "3.911.0", - "@smithy/config-resolver": "^4.3.2", - "@smithy/core": "^3.16.1", - "@smithy/fetch-http-handler": "^5.3.3", - "@smithy/hash-node": "^4.2.2", - "@smithy/invalid-dependency": "^4.2.2", - "@smithy/middleware-content-length": "^4.2.2", - "@smithy/middleware-endpoint": "^4.3.3", - "@smithy/middleware-retry": "^4.4.3", - "@smithy/middleware-serde": "^4.2.2", - "@smithy/middleware-stack": "^4.2.2", - "@smithy/node-config-provider": "^4.3.2", - "@smithy/node-http-handler": "^4.4.1", - "@smithy/protocol-http": "^5.3.2", - "@smithy/smithy-client": "^4.8.1", - "@smithy/types": "^4.7.1", - "@smithy/url-parser": "^4.2.2", + "@aws-sdk/core": "3.956.0", + "@aws-sdk/credential-provider-node": "3.956.0", + "@aws-sdk/middleware-host-header": "3.956.0", + "@aws-sdk/middleware-logger": "3.956.0", + "@aws-sdk/middleware-recursion-detection": "3.956.0", + "@aws-sdk/middleware-user-agent": "3.956.0", + "@aws-sdk/region-config-resolver": "3.956.0", + "@aws-sdk/types": "3.956.0", + "@aws-sdk/util-endpoints": "3.956.0", + "@aws-sdk/util-user-agent-browser": "3.956.0", + "@aws-sdk/util-user-agent-node": "3.956.0", + "@smithy/config-resolver": "^4.4.5", + "@smithy/core": "^3.20.0", + "@smithy/fetch-http-handler": "^5.3.8", + "@smithy/hash-node": "^4.2.7", + "@smithy/invalid-dependency": "^4.2.7", + "@smithy/middleware-content-length": "^4.2.7", + "@smithy/middleware-endpoint": "^4.4.1", + "@smithy/middleware-retry": "^4.4.17", + "@smithy/middleware-serde": "^4.2.8", + "@smithy/middleware-stack": "^4.2.7", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/node-http-handler": "^4.4.7", + "@smithy/protocol-http": "^5.3.7", + "@smithy/smithy-client": "^4.10.2", + "@smithy/types": "^4.11.0", + "@smithy/url-parser": "^4.2.7", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", - "@smithy/util-defaults-mode-browser": "^4.3.2", - "@smithy/util-defaults-mode-node": "^4.2.3", - "@smithy/util-endpoints": "^3.2.2", - "@smithy/util-middleware": "^4.2.2", - "@smithy/util-retry": "^4.2.2", + "@smithy/util-defaults-mode-browser": "^4.3.16", + "@smithy/util-defaults-mode-node": "^4.2.19", + "@smithy/util-endpoints": "^3.2.7", + "@smithy/util-middleware": "^4.2.7", + "@smithy/util-retry": "^4.2.7", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" }, @@ -402,48 +405,48 @@ } }, "node_modules/@aws-sdk/client-sso": { - "version": "3.911.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.911.0.tgz", - "integrity": "sha512-N9QAeMvN3D1ZyKXkQp4aUgC4wUMuA5E1HuVCkajc0bq1pnH4PIke36YlrDGGREqPlyLFrXCkws2gbL5p23vtlg==", + "version": "3.956.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.956.0.tgz", + "integrity": "sha512-TCxCa9B1IMILvk/7sig0fRQzff+M2zBQVZGWOJL8SAZq/gfElIMAf/nYjQwMhXjyq8PFDRGm4GN8ZhNKPeNleQ==", "license": "Apache-2.0", "optional": true, "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.911.0", - "@aws-sdk/middleware-host-header": "3.910.0", - "@aws-sdk/middleware-logger": "3.910.0", - "@aws-sdk/middleware-recursion-detection": "3.910.0", - "@aws-sdk/middleware-user-agent": "3.911.0", - "@aws-sdk/region-config-resolver": "3.910.0", - "@aws-sdk/types": "3.910.0", - "@aws-sdk/util-endpoints": "3.910.0", - "@aws-sdk/util-user-agent-browser": "3.910.0", - "@aws-sdk/util-user-agent-node": "3.911.0", - "@smithy/config-resolver": "^4.3.2", - "@smithy/core": "^3.16.1", - "@smithy/fetch-http-handler": "^5.3.3", - "@smithy/hash-node": "^4.2.2", - "@smithy/invalid-dependency": "^4.2.2", - "@smithy/middleware-content-length": "^4.2.2", - "@smithy/middleware-endpoint": "^4.3.3", - "@smithy/middleware-retry": "^4.4.3", - "@smithy/middleware-serde": "^4.2.2", - "@smithy/middleware-stack": "^4.2.2", - "@smithy/node-config-provider": "^4.3.2", - "@smithy/node-http-handler": "^4.4.1", - "@smithy/protocol-http": "^5.3.2", - "@smithy/smithy-client": "^4.8.1", - "@smithy/types": "^4.7.1", - "@smithy/url-parser": "^4.2.2", + "@aws-sdk/core": "3.956.0", + "@aws-sdk/middleware-host-header": "3.956.0", + "@aws-sdk/middleware-logger": "3.956.0", + "@aws-sdk/middleware-recursion-detection": "3.956.0", + "@aws-sdk/middleware-user-agent": "3.956.0", + "@aws-sdk/region-config-resolver": "3.956.0", + "@aws-sdk/types": "3.956.0", + "@aws-sdk/util-endpoints": "3.956.0", + "@aws-sdk/util-user-agent-browser": "3.956.0", + "@aws-sdk/util-user-agent-node": "3.956.0", + "@smithy/config-resolver": "^4.4.5", + "@smithy/core": "^3.20.0", + "@smithy/fetch-http-handler": "^5.3.8", + "@smithy/hash-node": "^4.2.7", + "@smithy/invalid-dependency": "^4.2.7", + "@smithy/middleware-content-length": "^4.2.7", + "@smithy/middleware-endpoint": "^4.4.1", + "@smithy/middleware-retry": "^4.4.17", + "@smithy/middleware-serde": "^4.2.8", + "@smithy/middleware-stack": "^4.2.7", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/node-http-handler": "^4.4.7", + "@smithy/protocol-http": "^5.3.7", + "@smithy/smithy-client": "^4.10.2", + "@smithy/types": "^4.11.0", + "@smithy/url-parser": "^4.2.7", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", - "@smithy/util-defaults-mode-browser": "^4.3.2", - "@smithy/util-defaults-mode-node": "^4.2.3", - "@smithy/util-endpoints": "^3.2.2", - "@smithy/util-middleware": "^4.2.2", - "@smithy/util-retry": "^4.2.2", + "@smithy/util-defaults-mode-browser": "^4.3.16", + "@smithy/util-defaults-mode-node": "^4.2.19", + "@smithy/util-endpoints": "^3.2.7", + "@smithy/util-middleware": "^4.2.7", + "@smithy/util-retry": "^4.2.7", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" }, @@ -452,23 +455,23 @@ } }, "node_modules/@aws-sdk/core": { - "version": "3.911.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.911.0.tgz", - "integrity": "sha512-k4QG9A+UCq/qlDJFmjozo6R0eXXfe++/KnCDMmajehIE9kh+b/5DqlGvAmbl9w4e92LOtrY6/DN3mIX1xs4sXw==", + "version": "3.956.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.956.0.tgz", + "integrity": "sha512-BMOCXZNz5z4cR3/SaNHUfeoZQUG/y39bLscdLUgg3RL6mDOhuINIqMc0qc6G3kpwDTLVdXikF4nmx2UrRK9y5A==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@aws-sdk/types": "3.910.0", - "@aws-sdk/xml-builder": "3.911.0", - "@smithy/core": "^3.16.1", - "@smithy/node-config-provider": "^4.3.2", - "@smithy/property-provider": "^4.2.2", - "@smithy/protocol-http": "^5.3.2", - "@smithy/signature-v4": "^5.3.2", - "@smithy/smithy-client": "^4.8.1", - "@smithy/types": "^4.7.1", + "@aws-sdk/types": "3.956.0", + "@aws-sdk/xml-builder": "3.956.0", + "@smithy/core": "^3.20.0", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/property-provider": "^4.2.7", + "@smithy/protocol-http": "^5.3.7", + "@smithy/signature-v4": "^5.3.7", + "@smithy/smithy-client": "^4.10.2", + "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", - "@smithy/util-middleware": "^4.2.2", + "@smithy/util-middleware": "^4.2.7", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" }, @@ -477,16 +480,16 @@ } }, "node_modules/@aws-sdk/credential-provider-cognito-identity": { - "version": "3.913.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.913.0.tgz", - "integrity": "sha512-AYZNpy3eEFzopzntLcrkEQQ1qyhg0V7BL8U77QdLSYtzoYvI9CqnWOGdWnNSEUp+Mpbk1VJyPzVfkDoDq5kX6g==", + "version": "3.956.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.956.0.tgz", + "integrity": "sha512-sqH7k7Uvbvc5V0Y8tB8CZoCd5KEuH5g30+wbrGac9s1D+TXXN6g8KnJhyYrHfwa1rJiY7B1mK80ENjG4LlUr0g==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@aws-sdk/client-cognito-identity": "3.913.0", - "@aws-sdk/types": "3.910.0", - "@smithy/property-provider": "^4.2.2", - "@smithy/types": "^4.7.1", + "@aws-sdk/client-cognito-identity": "3.956.0", + "@aws-sdk/types": "3.956.0", + "@smithy/property-provider": "^4.2.7", + "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "engines": { @@ -494,16 +497,16 @@ } }, "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.911.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.911.0.tgz", - "integrity": "sha512-6FWRwWn3LUZzLhqBXB+TPMW2ijCWUqGICSw8bVakEdODrvbiv1RT/MVUayzFwz/ek6e6NKZn6DbSWzx07N9Hjw==", + "version": "3.956.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.956.0.tgz", + "integrity": "sha512-aLJavJMPVTvhmggJ0pcdCKEWJk3sL9QkJkUIEoTzOou7HnxWS66N4sC5e8y27AF2nlnYfIxq3hkEiZlGi/vlfA==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@aws-sdk/core": "3.911.0", - "@aws-sdk/types": "3.910.0", - "@smithy/property-provider": "^4.2.2", - "@smithy/types": "^4.7.1", + "@aws-sdk/core": "3.956.0", + "@aws-sdk/types": "3.956.0", + "@smithy/property-provider": "^4.2.7", + "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "engines": { @@ -511,21 +514,21 @@ } }, "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.911.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.911.0.tgz", - "integrity": "sha512-xUlwKmIUW2fWP/eM3nF5u4CyLtOtyohlhGJ5jdsJokr3MrQ7w0tDITO43C9IhCn+28D5UbaiWnKw5ntkw7aVfA==", + "version": "3.956.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.956.0.tgz", + "integrity": "sha512-VsKzBNhwT6XJdW3HQX6o4KOHj1MAzSwA8/zCsT9mOGecozw1yeCcQPtlWDSlfsfygKVCXz7fiJzU03yl11NKMA==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@aws-sdk/core": "3.911.0", - "@aws-sdk/types": "3.910.0", - "@smithy/fetch-http-handler": "^5.3.3", - "@smithy/node-http-handler": "^4.4.1", - "@smithy/property-provider": "^4.2.2", - "@smithy/protocol-http": "^5.3.2", - "@smithy/smithy-client": "^4.8.1", - "@smithy/types": "^4.7.1", - "@smithy/util-stream": "^4.5.2", + "@aws-sdk/core": "3.956.0", + "@aws-sdk/types": "3.956.0", + "@smithy/fetch-http-handler": "^5.3.8", + "@smithy/node-http-handler": "^4.4.7", + "@smithy/property-provider": "^4.2.7", + "@smithy/protocol-http": "^5.3.7", + "@smithy/smithy-client": "^4.10.2", + "@smithy/types": "^4.11.0", + "@smithy/util-stream": "^4.5.8", "tslib": "^2.6.2" }, "engines": { @@ -533,24 +536,45 @@ } }, "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.913.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.913.0.tgz", - "integrity": "sha512-iR4c4NQ1OSRKQi0SxzpwD+wP1fCy+QNKtEyCajuVlD0pvmoIHdrm5THK9e+2/7/SsQDRhOXHJfLGxHapD74WJw==", + "version": "3.956.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.956.0.tgz", + "integrity": "sha512-TlDy+IGr0JIRBwnPdV31J1kWXEcfsR3OzcNVWQrguQdHeTw2lU5eft16kdizo6OruqcZRF/LvHBDwAWx4u51ww==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@aws-sdk/core": "3.911.0", - "@aws-sdk/credential-provider-env": "3.911.0", - "@aws-sdk/credential-provider-http": "3.911.0", - "@aws-sdk/credential-provider-process": "3.911.0", - "@aws-sdk/credential-provider-sso": "3.911.0", - "@aws-sdk/credential-provider-web-identity": "3.911.0", - "@aws-sdk/nested-clients": "3.911.0", - "@aws-sdk/types": "3.910.0", - "@smithy/credential-provider-imds": "^4.2.2", - "@smithy/property-provider": "^4.2.2", - "@smithy/shared-ini-file-loader": "^4.3.2", - "@smithy/types": "^4.7.1", + "@aws-sdk/core": "3.956.0", + "@aws-sdk/credential-provider-env": "3.956.0", + "@aws-sdk/credential-provider-http": "3.956.0", + "@aws-sdk/credential-provider-login": "3.956.0", + "@aws-sdk/credential-provider-process": "3.956.0", + "@aws-sdk/credential-provider-sso": "3.956.0", + "@aws-sdk/credential-provider-web-identity": "3.956.0", + "@aws-sdk/nested-clients": "3.956.0", + "@aws-sdk/types": "3.956.0", + "@smithy/credential-provider-imds": "^4.2.7", + "@smithy/property-provider": "^4.2.7", + "@smithy/shared-ini-file-loader": "^4.4.2", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-login": { + "version": "3.956.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.956.0.tgz", + "integrity": "sha512-p2Y62mdIlUpiyi5tvn8cKTja5kq1e3Rm5gm4wpNQ9caTayfkIEXyKrbP07iepTv60Coaylq9Fx6b5En/siAeGA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/core": "3.956.0", + "@aws-sdk/nested-clients": "3.956.0", + "@aws-sdk/types": "3.956.0", + "@smithy/property-provider": "^4.2.7", + "@smithy/protocol-http": "^5.3.7", + "@smithy/shared-ini-file-loader": "^4.4.2", + "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "engines": { @@ -558,23 +582,23 @@ } }, "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.913.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.913.0.tgz", - "integrity": "sha512-HQPLkKDxS83Q/nZKqg9bq4igWzYQeOMqhpx5LYs4u1GwsKeCsYrrfz12Iu4IHNWPp9EnGLcmdfbfYuqZGrsaSQ==", + "version": "3.956.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.956.0.tgz", + "integrity": "sha512-ITjp7uAQh17ljUsCWkPRmLjyFfupGlJVUfTLHnZJ+c7G0P0PDRquaM+fBSh0y33tauHsBa5fGnCCLRo5hy9sGQ==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@aws-sdk/credential-provider-env": "3.911.0", - "@aws-sdk/credential-provider-http": "3.911.0", - "@aws-sdk/credential-provider-ini": "3.913.0", - "@aws-sdk/credential-provider-process": "3.911.0", - "@aws-sdk/credential-provider-sso": "3.911.0", - "@aws-sdk/credential-provider-web-identity": "3.911.0", - "@aws-sdk/types": "3.910.0", - "@smithy/credential-provider-imds": "^4.2.2", - "@smithy/property-provider": "^4.2.2", - "@smithy/shared-ini-file-loader": "^4.3.2", - "@smithy/types": "^4.7.1", + "@aws-sdk/credential-provider-env": "3.956.0", + "@aws-sdk/credential-provider-http": "3.956.0", + "@aws-sdk/credential-provider-ini": "3.956.0", + "@aws-sdk/credential-provider-process": "3.956.0", + "@aws-sdk/credential-provider-sso": "3.956.0", + "@aws-sdk/credential-provider-web-identity": "3.956.0", + "@aws-sdk/types": "3.956.0", + "@smithy/credential-provider-imds": "^4.2.7", + "@smithy/property-provider": "^4.2.7", + "@smithy/shared-ini-file-loader": "^4.4.2", + "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "engines": { @@ -582,17 +606,17 @@ } }, "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.911.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.911.0.tgz", - "integrity": "sha512-mKshhV5jRQffZjbK9x7bs+uC2IsYKfpzYaBamFsEov3xtARCpOiKaIlM8gYKFEbHT2M+1R3rYYlhhl9ndVWS2g==", + "version": "3.956.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.956.0.tgz", + "integrity": "sha512-wpAex+/LGVWkHPchsn9FWy1ahFualIeSYq3ADFc262ljJjrltOWGh3+cu3OK3gTMkX6VEsl+lFvy1P7Bk7cgXA==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@aws-sdk/core": "3.911.0", - "@aws-sdk/types": "3.910.0", - "@smithy/property-provider": "^4.2.2", - "@smithy/shared-ini-file-loader": "^4.3.2", - "@smithy/types": "^4.7.1", + "@aws-sdk/core": "3.956.0", + "@aws-sdk/types": "3.956.0", + "@smithy/property-provider": "^4.2.7", + "@smithy/shared-ini-file-loader": "^4.4.2", + "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "engines": { @@ -600,19 +624,19 @@ } }, "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.911.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.911.0.tgz", - "integrity": "sha512-JAxd4uWe0Zc9tk6+N0cVxe9XtJVcOx6Ms0k933ZU9QbuRMH6xti/wnZxp/IvGIWIDzf5fhqiGyw5MSyDeI5b1w==", + "version": "3.956.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.956.0.tgz", + "integrity": "sha512-IRFSDF32x8TpOEYSGMcGQVJUiYuJaFkek0aCjW0klNIZHBF1YpflVpUarK9DJe4v4ryfVq3c0bqR/JFui8QFmw==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@aws-sdk/client-sso": "3.911.0", - "@aws-sdk/core": "3.911.0", - "@aws-sdk/token-providers": "3.911.0", - "@aws-sdk/types": "3.910.0", - "@smithy/property-provider": "^4.2.2", - "@smithy/shared-ini-file-loader": "^4.3.2", - "@smithy/types": "^4.7.1", + "@aws-sdk/client-sso": "3.956.0", + "@aws-sdk/core": "3.956.0", + "@aws-sdk/token-providers": "3.956.0", + "@aws-sdk/types": "3.956.0", + "@smithy/property-provider": "^4.2.7", + "@smithy/shared-ini-file-loader": "^4.4.2", + "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "engines": { @@ -620,18 +644,18 @@ } }, "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.911.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.911.0.tgz", - "integrity": "sha512-urIbXWWG+cm54RwwTFQuRwPH0WPsMFSDF2/H9qO2J2fKoHRURuyblFCyYG3aVKZGvFBhOizJYexf5+5w3CJKBw==", + "version": "3.956.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.956.0.tgz", + "integrity": "sha512-4YkmjwZC+qoUKlVOY9xNx7BTKRdJ1R1/Zjk2QSW5aWtwkk2e07ZUQvUpbW4vGpAxGm1K4EgRcowuSpOsDTh44Q==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@aws-sdk/core": "3.911.0", - "@aws-sdk/nested-clients": "3.911.0", - "@aws-sdk/types": "3.910.0", - "@smithy/property-provider": "^4.2.2", - "@smithy/shared-ini-file-loader": "^4.3.2", - "@smithy/types": "^4.7.1", + "@aws-sdk/core": "3.956.0", + "@aws-sdk/nested-clients": "3.956.0", + "@aws-sdk/types": "3.956.0", + "@smithy/property-provider": "^4.2.7", + "@smithy/shared-ini-file-loader": "^4.4.2", + "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "engines": { @@ -639,30 +663,31 @@ } }, "node_modules/@aws-sdk/credential-providers": { - "version": "3.913.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.913.0.tgz", - "integrity": "sha512-KnkvoLXGszXNV7IMLdUH2Smo+tr4MiHUp2zkkrhl+6uXdSWpEAhlARSA8OPIxgVMabUW1AWDumN7Km7z0GvnWg==", + "version": "3.956.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.956.0.tgz", + "integrity": "sha512-Fc8NWNkPZt61OIS6BRUWS+Po3z3nh3gE4w+4cZ083CdXxx4CCB82Oa0Fe2/E5l7p/z4vhEDXWwuJdiDQQXTplQ==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@aws-sdk/client-cognito-identity": "3.913.0", - "@aws-sdk/core": "3.911.0", - "@aws-sdk/credential-provider-cognito-identity": "3.913.0", - "@aws-sdk/credential-provider-env": "3.911.0", - "@aws-sdk/credential-provider-http": "3.911.0", - "@aws-sdk/credential-provider-ini": "3.913.0", - "@aws-sdk/credential-provider-node": "3.913.0", - "@aws-sdk/credential-provider-process": "3.911.0", - "@aws-sdk/credential-provider-sso": "3.911.0", - "@aws-sdk/credential-provider-web-identity": "3.911.0", - "@aws-sdk/nested-clients": "3.911.0", - "@aws-sdk/types": "3.910.0", - "@smithy/config-resolver": "^4.3.2", - "@smithy/core": "^3.16.1", - "@smithy/credential-provider-imds": "^4.2.2", - "@smithy/node-config-provider": "^4.3.2", - "@smithy/property-provider": "^4.2.2", - "@smithy/types": "^4.7.1", + "@aws-sdk/client-cognito-identity": "3.956.0", + "@aws-sdk/core": "3.956.0", + "@aws-sdk/credential-provider-cognito-identity": "3.956.0", + "@aws-sdk/credential-provider-env": "3.956.0", + "@aws-sdk/credential-provider-http": "3.956.0", + "@aws-sdk/credential-provider-ini": "3.956.0", + "@aws-sdk/credential-provider-login": "3.956.0", + "@aws-sdk/credential-provider-node": "3.956.0", + "@aws-sdk/credential-provider-process": "3.956.0", + "@aws-sdk/credential-provider-sso": "3.956.0", + "@aws-sdk/credential-provider-web-identity": "3.956.0", + "@aws-sdk/nested-clients": "3.956.0", + "@aws-sdk/types": "3.956.0", + "@smithy/config-resolver": "^4.4.5", + "@smithy/core": "^3.20.0", + "@smithy/credential-provider-imds": "^4.2.7", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/property-provider": "^4.2.7", + "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "engines": { @@ -670,15 +695,15 @@ } }, "node_modules/@aws-sdk/middleware-host-header": { - "version": "3.910.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.910.0.tgz", - "integrity": "sha512-F9Lqeu80/aTM6S/izZ8RtwSmjfhWjIuxX61LX+/9mxJyEkgaECRxv0chsLQsLHJumkGnXRy/eIyMLBhcTPF5vg==", + "version": "3.956.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.956.0.tgz", + "integrity": "sha512-JujNJDp/dj1DbsI0ntzhrz2uJ4jpumcKtr743eMpEhdboYjuu/UzY8/7n1h5JbgU9TNXgqE9lgQNa5QPG0Tvsg==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@aws-sdk/types": "3.910.0", - "@smithy/protocol-http": "^5.3.2", - "@smithy/types": "^4.7.1", + "@aws-sdk/types": "3.956.0", + "@smithy/protocol-http": "^5.3.7", + "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "engines": { @@ -686,14 +711,14 @@ } }, "node_modules/@aws-sdk/middleware-logger": { - "version": "3.910.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.910.0.tgz", - "integrity": "sha512-3LJyyfs1USvRuRDla1pGlzGRtXJBXD1zC9F+eE9Iz/V5nkmhyv52A017CvKWmYoR0DM9dzjLyPOI0BSSppEaTw==", + "version": "3.956.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.956.0.tgz", + "integrity": "sha512-Qff39yEOPYgRsm4SrkHOvS0nSoxXILYnC8Akp0uMRi2lOcZVyXL3WCWqIOtI830qVI4GPa796sleKguxx50RHg==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@aws-sdk/types": "3.910.0", - "@smithy/types": "^4.7.1", + "@aws-sdk/types": "3.956.0", + "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "engines": { @@ -701,16 +726,16 @@ } }, "node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.910.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.910.0.tgz", - "integrity": "sha512-m/oLz0EoCy+WoIVBnXRXJ4AtGpdl0kPE7U+VH9TsuUzHgxY1Re/176Q1HWLBRVlz4gr++lNsgsMWEC+VnAwMpw==", + "version": "3.956.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.956.0.tgz", + "integrity": "sha512-/f4JxL2kSCYhy63wovqts6SJkpalSLvuFe78ozt3ClrGoHGyr69o7tPRYx5U7azLgvrIGjsWUyTayeAk3YHIVQ==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@aws-sdk/types": "3.910.0", - "@aws/lambda-invoke-store": "^0.0.1", - "@smithy/protocol-http": "^5.3.2", - "@smithy/types": "^4.7.1", + "@aws-sdk/types": "3.956.0", + "@aws/lambda-invoke-store": "^0.2.2", + "@smithy/protocol-http": "^5.3.7", + "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "engines": { @@ -718,18 +743,18 @@ } }, "node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.911.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.911.0.tgz", - "integrity": "sha512-rY3LvGvgY/UI0nmt5f4DRzjEh8135A2TeHcva1bgOmVfOI4vkkGfA20sNRqerOkSO6hPbkxJapO50UJHFzmmyA==", + "version": "3.956.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.956.0.tgz", + "integrity": "sha512-azH8OJ0AIe3NafaTNvJorG/ALaLNTYwVKtyaSeQKOvaL8TNuBVuDnM5iHCiWryIaRgZotomqycwyfNKLw2D3JQ==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@aws-sdk/core": "3.911.0", - "@aws-sdk/types": "3.910.0", - "@aws-sdk/util-endpoints": "3.910.0", - "@smithy/core": "^3.16.1", - "@smithy/protocol-http": "^5.3.2", - "@smithy/types": "^4.7.1", + "@aws-sdk/core": "3.956.0", + "@aws-sdk/types": "3.956.0", + "@aws-sdk/util-endpoints": "3.956.0", + "@smithy/core": "^3.20.0", + "@smithy/protocol-http": "^5.3.7", + "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "engines": { @@ -737,48 +762,48 @@ } }, "node_modules/@aws-sdk/nested-clients": { - "version": "3.911.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.911.0.tgz", - "integrity": "sha512-lp/sXbdX/S0EYaMYPVKga0omjIUbNNdFi9IJITgKZkLC6CzspihIoHd5GIdl4esMJevtTQQfkVncXTFkf/a4YA==", + "version": "3.956.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.956.0.tgz", + "integrity": "sha512-GHDQMkxoWpi3eTrhWGmghw0gsZJ5rM1ERHfBFhlhduCdtV3TyhKVmDgFG84KhU8v18dcVpSp3Pu3KwH7j1tgIg==", "license": "Apache-2.0", "optional": true, "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.911.0", - "@aws-sdk/middleware-host-header": "3.910.0", - "@aws-sdk/middleware-logger": "3.910.0", - "@aws-sdk/middleware-recursion-detection": "3.910.0", - "@aws-sdk/middleware-user-agent": "3.911.0", - "@aws-sdk/region-config-resolver": "3.910.0", - "@aws-sdk/types": "3.910.0", - "@aws-sdk/util-endpoints": "3.910.0", - "@aws-sdk/util-user-agent-browser": "3.910.0", - "@aws-sdk/util-user-agent-node": "3.911.0", - "@smithy/config-resolver": "^4.3.2", - "@smithy/core": "^3.16.1", - "@smithy/fetch-http-handler": "^5.3.3", - "@smithy/hash-node": "^4.2.2", - "@smithy/invalid-dependency": "^4.2.2", - "@smithy/middleware-content-length": "^4.2.2", - "@smithy/middleware-endpoint": "^4.3.3", - "@smithy/middleware-retry": "^4.4.3", - "@smithy/middleware-serde": "^4.2.2", - "@smithy/middleware-stack": "^4.2.2", - "@smithy/node-config-provider": "^4.3.2", - "@smithy/node-http-handler": "^4.4.1", - "@smithy/protocol-http": "^5.3.2", - "@smithy/smithy-client": "^4.8.1", - "@smithy/types": "^4.7.1", - "@smithy/url-parser": "^4.2.2", + "@aws-sdk/core": "3.956.0", + "@aws-sdk/middleware-host-header": "3.956.0", + "@aws-sdk/middleware-logger": "3.956.0", + "@aws-sdk/middleware-recursion-detection": "3.956.0", + "@aws-sdk/middleware-user-agent": "3.956.0", + "@aws-sdk/region-config-resolver": "3.956.0", + "@aws-sdk/types": "3.956.0", + "@aws-sdk/util-endpoints": "3.956.0", + "@aws-sdk/util-user-agent-browser": "3.956.0", + "@aws-sdk/util-user-agent-node": "3.956.0", + "@smithy/config-resolver": "^4.4.5", + "@smithy/core": "^3.20.0", + "@smithy/fetch-http-handler": "^5.3.8", + "@smithy/hash-node": "^4.2.7", + "@smithy/invalid-dependency": "^4.2.7", + "@smithy/middleware-content-length": "^4.2.7", + "@smithy/middleware-endpoint": "^4.4.1", + "@smithy/middleware-retry": "^4.4.17", + "@smithy/middleware-serde": "^4.2.8", + "@smithy/middleware-stack": "^4.2.7", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/node-http-handler": "^4.4.7", + "@smithy/protocol-http": "^5.3.7", + "@smithy/smithy-client": "^4.10.2", + "@smithy/types": "^4.11.0", + "@smithy/url-parser": "^4.2.7", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", - "@smithy/util-defaults-mode-browser": "^4.3.2", - "@smithy/util-defaults-mode-node": "^4.2.3", - "@smithy/util-endpoints": "^3.2.2", - "@smithy/util-middleware": "^4.2.2", - "@smithy/util-retry": "^4.2.2", + "@smithy/util-defaults-mode-browser": "^4.3.16", + "@smithy/util-defaults-mode-node": "^4.2.19", + "@smithy/util-endpoints": "^3.2.7", + "@smithy/util-middleware": "^4.2.7", + "@smithy/util-retry": "^4.2.7", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" }, @@ -787,17 +812,16 @@ } }, "node_modules/@aws-sdk/region-config-resolver": { - "version": "3.910.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.910.0.tgz", - "integrity": "sha512-gzQAkuHI3xyG6toYnH/pju+kc190XmvnB7X84vtN57GjgdQJICt9So/BD0U6h+eSfk9VBnafkVrAzBzWMEFZVw==", + "version": "3.956.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.956.0.tgz", + "integrity": "sha512-byU5XYekW7+rZ3e067y038wlrpnPkdI4fMxcHCHrv+TAfzl8CCk5xLyzerQtXZR8cVPVOXuaYWe1zKW0uCnXUA==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@aws-sdk/types": "3.910.0", - "@smithy/node-config-provider": "^4.3.2", - "@smithy/types": "^4.7.1", - "@smithy/util-config-provider": "^4.2.0", - "@smithy/util-middleware": "^4.2.2", + "@aws-sdk/types": "3.956.0", + "@smithy/config-resolver": "^4.4.5", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "engines": { @@ -805,18 +829,18 @@ } }, "node_modules/@aws-sdk/token-providers": { - "version": "3.911.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.911.0.tgz", - "integrity": "sha512-O1c5F1pbEImgEe3Vr8j1gpWu69UXWj3nN3vvLGh77hcrG5dZ8I27tSP5RN4Labm8Dnji/6ia+vqSYpN8w6KN5A==", + "version": "3.956.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.956.0.tgz", + "integrity": "sha512-I01Q9yDeG9oXge14u/bubtSdBpok/rTsPp2AQwy5xj/5PatRTHPbUTP6tef3AH/lFCAqkI0nncIcgx6zikDdUQ==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@aws-sdk/core": "3.911.0", - "@aws-sdk/nested-clients": "3.911.0", - "@aws-sdk/types": "3.910.0", - "@smithy/property-provider": "^4.2.2", - "@smithy/shared-ini-file-loader": "^4.3.2", - "@smithy/types": "^4.7.1", + "@aws-sdk/core": "3.956.0", + "@aws-sdk/nested-clients": "3.956.0", + "@aws-sdk/types": "3.956.0", + "@smithy/property-provider": "^4.2.7", + "@smithy/shared-ini-file-loader": "^4.4.2", + "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "engines": { @@ -824,13 +848,13 @@ } }, "node_modules/@aws-sdk/types": { - "version": "3.910.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.910.0.tgz", - "integrity": "sha512-o67gL3vjf4nhfmuSUNNkit0d62QJEwwHLxucwVJkR/rw9mfUtAWsgBs8Tp16cdUbMgsyQtCQilL8RAJDoGtadQ==", + "version": "3.956.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.956.0.tgz", + "integrity": "sha512-DMRU/p9wAlAJxEjegnLwduCA8YP2pcT/sIJ+17KSF38c5cC6CbBhykwbZLECTo+zYzoFrOqeLbqE6paH8Gx3ug==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@smithy/types": "^4.7.1", + "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "engines": { @@ -838,16 +862,16 @@ } }, "node_modules/@aws-sdk/util-endpoints": { - "version": "3.910.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.910.0.tgz", - "integrity": "sha512-6XgdNe42ibP8zCQgNGDWoOF53RfEKzpU/S7Z29FTTJ7hcZv0SytC0ZNQQZSx4rfBl036YWYwJRoJMlT4AA7q9A==", + "version": "3.956.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.956.0.tgz", + "integrity": "sha512-xZ5CBoubS4rs9JkFniKNShDtfqxaMUnwaebYMoybZm070q9+omFkQkJYXl7kopTViEgZgQl1sAsAkrawBM8qEQ==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@aws-sdk/types": "3.910.0", - "@smithy/types": "^4.7.1", - "@smithy/url-parser": "^4.2.2", - "@smithy/util-endpoints": "^3.2.2", + "@aws-sdk/types": "3.956.0", + "@smithy/types": "^4.11.0", + "@smithy/url-parser": "^4.2.7", + "@smithy/util-endpoints": "^3.2.7", "tslib": "^2.6.2" }, "engines": { @@ -855,9 +879,9 @@ } }, "node_modules/@aws-sdk/util-locate-window": { - "version": "3.893.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.893.0.tgz", - "integrity": "sha512-T89pFfgat6c8nMmpI8eKjBcDcgJq36+m9oiXbcUzeU55MP9ZuGgBomGjGnHaEyF36jenW9gmg3NfZDm0AO2XPg==", + "version": "3.953.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.953.0.tgz", + "integrity": "sha512-mPxK+I1LcrgC/RSa3G5AMAn8eN2Ay0VOgw8lSRmV1jCtO+iYvNeCqOdxoJUjOW6I5BA4niIRWqVORuRP07776Q==", "license": "Apache-2.0", "optional": true, "dependencies": { @@ -868,29 +892,29 @@ } }, "node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.910.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.910.0.tgz", - "integrity": "sha512-iOdrRdLZHrlINk9pezNZ82P/VxO/UmtmpaOAObUN+xplCUJu31WNM2EE/HccC8PQw6XlAudpdA6HDTGiW6yVGg==", + "version": "3.956.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.956.0.tgz", + "integrity": "sha512-s8KwYR3HqiGNni7a1DN2P3RUog64QoBQ6VCSzJkHBWb6++8KSOpqeeDkfmEz+22y1LOne+bRrpDGKa0aqOc3rQ==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@aws-sdk/types": "3.910.0", - "@smithy/types": "^4.7.1", + "@aws-sdk/types": "3.956.0", + "@smithy/types": "^4.11.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.911.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.911.0.tgz", - "integrity": "sha512-3l+f6ooLF6Z6Lz0zGi7vSKSUYn/EePPizv88eZQpEAFunBHv+CSVNPtxhxHfkm7X9tTsV4QGZRIqo3taMLolmA==", + "version": "3.956.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.956.0.tgz", + "integrity": "sha512-H0r6ol3Rr63/3xvrUsLqHps+cA7VkM7uCU5NtuTHnMbv3uYYTKf9M2XFHAdVewmmRgssTzvqemrARc8Ji3SNvg==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@aws-sdk/middleware-user-agent": "3.911.0", - "@aws-sdk/types": "3.910.0", - "@smithy/node-config-provider": "^4.3.2", - "@smithy/types": "^4.7.1", + "@aws-sdk/middleware-user-agent": "3.956.0", + "@aws-sdk/types": "3.956.0", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "engines": { @@ -906,13 +930,13 @@ } }, "node_modules/@aws-sdk/xml-builder": { - "version": "3.911.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.911.0.tgz", - "integrity": "sha512-/yh3oe26bZfCVGrIMRM9Z4hvvGJD+qx5tOLlydOkuBkm72aXON7D9+MucjJXTAcI8tF2Yq+JHa0478eHQOhnLg==", + "version": "3.956.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.956.0.tgz", + "integrity": "sha512-x/IvXUeQYNUEQojpRIQpFt4X7XGxqzjUlXFRdwaTCtTz3q1droXVJvYOhnX3KiMgzeHGlBJfY4Nmq3oZNEUGFw==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@smithy/types": "^4.7.1", + "@smithy/types": "^4.11.0", "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" }, @@ -921,9 +945,9 @@ } }, "node_modules/@aws/lambda-invoke-store": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.0.1.tgz", - "integrity": "sha512-ORHRQ2tmvnBXc8t/X9Z8IcSbBA4xTLKuN873FopzklHMeqBst7YG0d+AX97inkvDX+NChYtSr+qGfcqGFaI8Zw==", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.2.2.tgz", + "integrity": "sha512-C0NBLsIqzDIae8HFw9YIrIBsbc0xTiOtt7fAukGPnqQ/+zZNaq+4jhuccltK0QuWHBnNm/a6kLIRA6GFiM10eg==", "license": "Apache-2.0", "optional": true, "engines": { @@ -1033,9 +1057,9 @@ } }, "node_modules/@azure/core-rest-pipeline": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.22.1.tgz", - "integrity": "sha512-UVZlVLfLyz6g3Hy7GNDpooMQonUygH7ghdiSASOOHy97fKj/mPLqgDX7aidOijn+sCMU+WU8NjlPlNTgnvbcGA==", + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.22.2.tgz", + "integrity": "sha512-MzHym+wOi8CLUlKCQu12de0nwcq9k9Kuv43j4Wa++CsCpJwps2eeBQwD2Bu8snkxTtDKDx4GwjuR9E8yC8LNrg==", "license": "MIT", "dependencies": { "@azure/abort-controller": "^2.1.2", @@ -1184,33 +1208,33 @@ } }, "node_modules/@azure/msal-browser": { - "version": "4.25.1", - "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-4.25.1.tgz", - "integrity": "sha512-kAdOSNjvMbeBmEyd5WnddGmIpKCbAAGj4Gg/1iURtF+nHmIfS0+QUBBO3uaHl7CBB2R1SEAbpOgxycEwrHOkFA==", + "version": "4.27.0", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-4.27.0.tgz", + "integrity": "sha512-bZ8Pta6YAbdd0o0PEaL1/geBsPrLEnyY/RDWqvF1PP9RUH8EMLvUMGoZFYS6jSlUan6KZ9IMTLCnwpWWpQRK/w==", "license": "MIT", "dependencies": { - "@azure/msal-common": "15.13.0" + "@azure/msal-common": "15.13.3" }, "engines": { "node": ">=0.8.0" } }, "node_modules/@azure/msal-common": { - "version": "15.13.0", - "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-15.13.0.tgz", - "integrity": "sha512-8oF6nj02qX7eE/6+wFT5NluXRHc05AgdCC3fJnkjiJooq8u7BcLmxaYYSwc2AfEkWRMRi6Eyvvbeqk4U4412Ag==", + "version": "15.13.3", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-15.13.3.tgz", + "integrity": "sha512-shSDU7Ioecya+Aob5xliW9IGq1Ui8y4EVSdWGyI1Gbm4Vg61WpP95LuzcY214/wEjSn6w4PZYD4/iVldErHayQ==", "license": "MIT", "engines": { "node": ">=0.8.0" } }, "node_modules/@azure/msal-node": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-3.8.0.tgz", - "integrity": "sha512-23BXm82Mp5XnRhrcd4mrHa0xuUNRp96ivu3nRatrfdAqjoeWAGyD0eEAafxAOHAEWWmdlyFK4ELFcdziXyw2sA==", + "version": "3.8.4", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-3.8.4.tgz", + "integrity": "sha512-lvuAwsDpPDE/jSuVQOBMpLbXuVuLsPNRwWCyK3/6bPlBk0fGWegqoZ0qjZclMWyQ2JNvIY3vHY7hoFmFmFQcOw==", "license": "MIT", "dependencies": { - "@azure/msal-common": "15.13.0", + "@azure/msal-common": "15.13.3", "jsonwebtoken": "^9.0.0", "uuid": "^8.3.0" }, @@ -3339,9 +3363,9 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", "dev": true, "license": "MIT", "engines": { @@ -3383,22 +3407,6 @@ "concat-map": "0.0.1" } }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -3412,19 +3420,6 @@ "node": "*" } }, - "node_modules/@eslint/eslintrc/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@fastify/busboy": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", @@ -3653,7 +3648,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", - "dev": true, "license": "MIT", "engines": { "node": "20 || >=22" @@ -3663,7 +3657,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", - "dev": true, "license": "MIT", "dependencies": { "@isaacs/balanced-match": "^4.0.1" @@ -3935,9 +3928,9 @@ } }, "node_modules/@mongodb-js/saslprep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.3.2.tgz", - "integrity": "sha512-QgA5AySqB27cGTXBFmnpifAi7HxoGUeezwo6p9dI03MuDB6Pp33zgclqVb6oVK3j6I9Vesg0+oojW2XxB59SGg==", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.4.4.tgz", + "integrity": "sha512-p7X/ytJDIdwUfFL/CLOhKgdfJe1Fa8uw9seJYvdOmnP9JBWGWHW69HkOixXS6Wy9yvGf1MbhcS6lVmrhy4jm2g==", "license": "MIT", "optional": true, "dependencies": { @@ -4411,38 +4404,6 @@ } } }, - "node_modules/@rollup/plugin-babel/node_modules/@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" - }, - "engines": { - "node": ">= 8.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" - } - }, - "node_modules/@rollup/plugin-babel/node_modules/@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@rollup/plugin-babel/node_modules/estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", - "dev": true, - "license": "MIT" - }, "node_modules/@rollup/plugin-node-resolve": { "version": "15.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.3.1.tgz", @@ -4468,6 +4429,42 @@ } } }, + "node_modules/@rollup/plugin-node-resolve/node_modules/@rollup/pluginutils": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", + "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-node-resolve/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/@rollup/plugin-replace": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz", @@ -4482,38 +4479,6 @@ "rollup": "^1.20.0 || ^2.0.0" } }, - "node_modules/@rollup/plugin-replace/node_modules/@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" - }, - "engines": { - "node": ">= 8.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" - } - }, - "node_modules/@rollup/plugin-replace/node_modules/@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@rollup/plugin-replace/node_modules/estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", - "dev": true, - "license": "MIT" - }, "node_modules/@rollup/plugin-replace/node_modules/magic-string": { "version": "0.25.9", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", @@ -4574,45 +4539,41 @@ } }, "node_modules/@rollup/pluginutils": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", - "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^4.0.2" + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" }, "engines": { - "node": ">=14.0.0" + "node": ">= 8.0.0" }, "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } + "rollup": "^1.20.0||^2.0.0" } }, - "node_modules/@rollup/pluginutils/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "node_modules/@rollup/pluginutils/node_modules/@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } + "license": "MIT" + }, + "node_modules/@rollup/pluginutils/node_modules/estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true, + "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.5.tgz", - "integrity": "sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.5.tgz", + "integrity": "sha512-iDGS/h7D8t7tvZ1t6+WPK04KD0MwzLZrG0se1hzBjSi5fyxlsiggoJHwh18PCFNn7tG43OWb6pdZ6Y+rMlmyNQ==", "cpu": [ "arm" ], @@ -4624,9 +4585,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.5.tgz", - "integrity": "sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.5.tgz", + "integrity": "sha512-wrSAViWvZHBMMlWk6EJhvg8/rjxzyEhEdgfMMjREHEq11EtJ6IP6yfcCH57YAEca2Oe3FNCE9DSTgU70EIGmVw==", "cpu": [ "arm64" ], @@ -4638,9 +4599,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.5.tgz", - "integrity": "sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.5.tgz", + "integrity": "sha512-S87zZPBmRO6u1YXQLwpveZm4JfPpAa6oHBX7/ghSiGH3rz/KDgAu1rKdGutV+WUI6tKDMbaBJomhnT30Y2t4VQ==", "cpu": [ "arm64" ], @@ -4652,9 +4613,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.5.tgz", - "integrity": "sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.5.tgz", + "integrity": "sha512-YTbnsAaHo6VrAczISxgpTva8EkfQus0VPEVJCEaboHtZRIb6h6j0BNxRBOwnDciFTZLDPW5r+ZBmhL/+YpTZgA==", "cpu": [ "x64" ], @@ -4666,9 +4627,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.5.tgz", - "integrity": "sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.5.tgz", + "integrity": "sha512-1T8eY2J8rKJWzaznV7zedfdhD1BqVs1iqILhmHDq/bqCUZsrMt+j8VCTHhP0vdfbHK3e1IQ7VYx3jlKqwlf+vw==", "cpu": [ "arm64" ], @@ -4680,9 +4641,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.5.tgz", - "integrity": "sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.5.tgz", + "integrity": "sha512-sHTiuXyBJApxRn+VFMaw1U+Qsz4kcNlxQ742snICYPrY+DDL8/ZbaC4DVIB7vgZmp3jiDaKA0WpBdP0aqPJoBQ==", "cpu": [ "x64" ], @@ -4694,9 +4655,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.5.tgz", - "integrity": "sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.5.tgz", + "integrity": "sha512-dV3T9MyAf0w8zPVLVBptVlzaXxka6xg1f16VAQmjg+4KMSTWDvhimI/Y6mp8oHwNrmnmVl9XxJ/w/mO4uIQONA==", "cpu": [ "arm" ], @@ -4708,9 +4669,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.5.tgz", - "integrity": "sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.5.tgz", + "integrity": "sha512-wIGYC1x/hyjP+KAu9+ewDI+fi5XSNiUi9Bvg6KGAh2TsNMA3tSEs+Sh6jJ/r4BV/bx/CyWu2ue9kDnIdRyafcQ==", "cpu": [ "arm" ], @@ -4722,9 +4683,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.5.tgz", - "integrity": "sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.5.tgz", + "integrity": "sha512-Y+qVA0D9d0y2FRNiG9oM3Hut/DgODZbU9I8pLLPwAsU0tUKZ49cyV1tzmB/qRbSzGvY8lpgGkJuMyuhH7Ma+Vg==", "cpu": [ "arm64" ], @@ -4736,9 +4697,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.5.tgz", - "integrity": "sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.5.tgz", + "integrity": "sha512-juaC4bEgJsyFVfqhtGLz8mbopaWD+WeSOYr5E16y+1of6KQjc0BpwZLuxkClqY1i8sco+MdyoXPNiCkQou09+g==", "cpu": [ "arm64" ], @@ -4750,9 +4711,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.5.tgz", - "integrity": "sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.5.tgz", + "integrity": "sha512-rIEC0hZ17A42iXtHX+EPJVL/CakHo+tT7W0pbzdAGuWOt2jxDFh7A/lRhsNHBcqL4T36+UiAgwO8pbmn3dE8wA==", "cpu": [ "loong64" ], @@ -4764,9 +4725,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.5.tgz", - "integrity": "sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.5.tgz", + "integrity": "sha512-T7l409NhUE552RcAOcmJHj3xyZ2h7vMWzcwQI0hvn5tqHh3oSoclf9WgTl+0QqffWFG8MEVZZP1/OBglKZx52Q==", "cpu": [ "ppc64" ], @@ -4778,9 +4739,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.5.tgz", - "integrity": "sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.5.tgz", + "integrity": "sha512-7OK5/GhxbnrMcxIFoYfhV/TkknarkYC1hqUw1wU2xUN3TVRLNT5FmBv4KkheSG2xZ6IEbRAhTooTV2+R5Tk0lQ==", "cpu": [ "riscv64" ], @@ -4792,9 +4753,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.5.tgz", - "integrity": "sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.5.tgz", + "integrity": "sha512-GwuDBE/PsXaTa76lO5eLJTyr2k8QkPipAyOrs4V/KJufHCZBJ495VCGJol35grx9xryk4V+2zd3Ri+3v7NPh+w==", "cpu": [ "riscv64" ], @@ -4806,9 +4767,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.5.tgz", - "integrity": "sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.5.tgz", + "integrity": "sha512-IAE1Ziyr1qNfnmiQLHBURAD+eh/zH1pIeJjeShleII7Vj8kyEm2PF77o+lf3WTHDpNJcu4IXJxNO0Zluro8bOw==", "cpu": [ "s390x" ], @@ -4820,9 +4781,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.5.tgz", - "integrity": "sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.5.tgz", + "integrity": "sha512-Pg6E+oP7GvZ4XwgRJBuSXZjcqpIW3yCBhK4BcsANvb47qMvAbCjR6E+1a/U2WXz1JJxp9/4Dno3/iSJLcm5auw==", "cpu": [ "x64" ], @@ -4834,9 +4795,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.5.tgz", - "integrity": "sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.5.tgz", + "integrity": "sha512-txGtluxDKTxaMDzUduGP0wdfng24y1rygUMnmlUJ88fzCCULCLn7oE5kb2+tRB+MWq1QDZT6ObT5RrR8HFRKqg==", "cpu": [ "x64" ], @@ -4848,9 +4809,9 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.5.tgz", - "integrity": "sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.5.tgz", + "integrity": "sha512-3DFiLPnTxiOQV993fMc+KO8zXHTcIjgaInrqlG8zDp1TlhYl6WgrOHuJkJQ6M8zHEcntSJsUp1XFZSY8C1DYbg==", "cpu": [ "arm64" ], @@ -4862,9 +4823,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.5.tgz", - "integrity": "sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.5.tgz", + "integrity": "sha512-nggc/wPpNTgjGg75hu+Q/3i32R00Lq1B6N1DO7MCU340MRKL3WZJMjA9U4K4gzy3dkZPXm9E1Nc81FItBVGRlA==", "cpu": [ "arm64" ], @@ -4876,9 +4837,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.5.tgz", - "integrity": "sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.5.tgz", + "integrity": "sha512-U/54pTbdQpPLBdEzCT6NBCFAfSZMvmjr0twhnD9f4EIvlm9wy3jjQ38yQj1AGznrNO65EWQMgm/QUjuIVrYF9w==", "cpu": [ "ia32" ], @@ -4890,9 +4851,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.5.tgz", - "integrity": "sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.5.tgz", + "integrity": "sha512-2NqKgZSuLH9SXBBV2dWNRCZmocgSOx8OJSdpRaEcRlIfX8YrKxUT6z0F1NpvDVhOsl190UFTRh2F2WDWWCYp3A==", "cpu": [ "x64" ], @@ -4904,9 +4865,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.5.tgz", - "integrity": "sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.5.tgz", + "integrity": "sha512-JRpZUhCfhZ4keB5v0fe02gQJy05GqboPOaxvjugW04RLSYYoB/9t2lx2u/tMs/Na/1NXfY8QYjgRljRpN+MjTQ==", "cpu": [ "x64" ], @@ -5005,13 +4966,13 @@ } }, "node_modules/@smithy/abort-controller": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.2.3.tgz", - "integrity": "sha512-xWL9Mf8b7tIFuAlpjKtRPnHrR8XVrwTj5NPYO/QwZPtc0SDLsPxb56V5tzi5yspSMytISHybifez+4jlrx0vkQ==", + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.2.7.tgz", + "integrity": "sha512-rzMY6CaKx2qxrbYbqjXWS0plqEy7LOdKHS0bg4ixJ6aoGDPNUcLWk/FRNuCILh7GKLG9TFUXYYeQQldMBBwuyw==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@smithy/types": "^4.8.0", + "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "engines": { @@ -5019,16 +4980,17 @@ } }, "node_modules/@smithy/config-resolver": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.3.3.tgz", - "integrity": "sha512-xSql8A1Bl41O9JvGU/CtgiLBlwkvpHTSKRlvz9zOBvBCPjXghZ6ZkcVzmV2f7FLAA+80+aqKmIOmy8pEDrtCaw==", + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.4.5.tgz", + "integrity": "sha512-HAGoUAFYsUkoSckuKbCPayECeMim8pOu+yLy1zOxt1sifzEbrsRpYa+mKcMdiHKMeiqOibyPG0sFJnmaV/OGEg==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@smithy/node-config-provider": "^4.3.3", - "@smithy/types": "^4.8.0", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/types": "^4.11.0", "@smithy/util-config-provider": "^4.2.0", - "@smithy/util-middleware": "^4.2.3", + "@smithy/util-endpoints": "^3.2.7", + "@smithy/util-middleware": "^4.2.7", "tslib": "^2.6.2" }, "engines": { @@ -5036,19 +4998,19 @@ } }, "node_modules/@smithy/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.17.0.tgz", - "integrity": "sha512-Tir3DbfoTO97fEGUZjzGeoXgcQAUBRDTmuH9A8lxuP8ATrgezrAJ6cLuRvwdKN4ZbYNlHgKlBX69Hyu3THYhtg==", + "version": "3.20.0", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.20.0.tgz", + "integrity": "sha512-WsSHCPq/neD5G/MkK4csLI5Y5Pkd9c1NMfpYEKeghSGaD4Ja1qLIohRQf2D5c1Uy5aXp76DeKHkzWZ9KAlHroQ==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@smithy/middleware-serde": "^4.2.3", - "@smithy/protocol-http": "^5.3.3", - "@smithy/types": "^4.8.0", + "@smithy/middleware-serde": "^4.2.8", + "@smithy/protocol-http": "^5.3.7", + "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", - "@smithy/util-middleware": "^4.2.3", - "@smithy/util-stream": "^4.5.3", + "@smithy/util-middleware": "^4.2.7", + "@smithy/util-stream": "^4.5.8", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" @@ -5058,16 +5020,16 @@ } }, "node_modules/@smithy/credential-provider-imds": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.3.tgz", - "integrity": "sha512-hA1MQ/WAHly4SYltJKitEsIDVsNmXcQfYBRv2e+q04fnqtAX5qXaybxy/fhUeAMCnQIdAjaGDb04fMHQefWRhw==", + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.7.tgz", + "integrity": "sha512-CmduWdCiILCRNbQWFR0OcZlUPVtyE49Sr8yYL0rZQ4D/wKxiNzBNS/YHemvnbkIWj623fplgkexUd/c9CAKdoA==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@smithy/node-config-provider": "^4.3.3", - "@smithy/property-provider": "^4.2.3", - "@smithy/types": "^4.8.0", - "@smithy/url-parser": "^4.2.3", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/property-provider": "^4.2.7", + "@smithy/types": "^4.11.0", + "@smithy/url-parser": "^4.2.7", "tslib": "^2.6.2" }, "engines": { @@ -5075,15 +5037,15 @@ } }, "node_modules/@smithy/fetch-http-handler": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.4.tgz", - "integrity": "sha512-bwigPylvivpRLCm+YK9I5wRIYjFESSVwl8JQ1vVx/XhCw0PtCi558NwTnT2DaVCl5pYlImGuQTSwMsZ+pIavRw==", + "version": "5.3.8", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.8.tgz", + "integrity": "sha512-h/Fi+o7mti4n8wx1SR6UHWLaakwHRx29sizvp8OOm7iqwKGFneT06GCSFhml6Bha5BT6ot5pj3CYZnCHhGC2Rg==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@smithy/protocol-http": "^5.3.3", - "@smithy/querystring-builder": "^4.2.3", - "@smithy/types": "^4.8.0", + "@smithy/protocol-http": "^5.3.7", + "@smithy/querystring-builder": "^4.2.7", + "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" }, @@ -5092,13 +5054,13 @@ } }, "node_modules/@smithy/hash-node": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.2.3.tgz", - "integrity": "sha512-6+NOdZDbfuU6s1ISp3UOk5Rg953RJ2aBLNLLBEcamLjHAg1Po9Ha7QIB5ZWhdRUVuOUrT8BVFR+O2KIPmw027g==", + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.2.7.tgz", + "integrity": "sha512-PU/JWLTBCV1c8FtB8tEFnY4eV1tSfBc7bDBADHfn1K+uRbPgSJ9jnJp0hyjiFN2PMdPzxsf1Fdu0eo9fJ760Xw==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@smithy/types": "^4.8.0", + "@smithy/types": "^4.11.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" @@ -5108,13 +5070,13 @@ } }, "node_modules/@smithy/invalid-dependency": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.2.3.tgz", - "integrity": "sha512-Cc9W5DwDuebXEDMpOpl4iERo8I0KFjTnomK2RMdhhR87GwrSmUmwMxS4P5JdRf+LsjOdIqumcerwRgYMr/tZ9Q==", + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.2.7.tgz", + "integrity": "sha512-ncvgCr9a15nPlkhIUx3CU4d7E7WEuVJOV7fS7nnK2hLtPK9tYRBkMHQbhXU1VvvKeBm/O0x26OEoBq+ngFpOEQ==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@smithy/types": "^4.8.0", + "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "engines": { @@ -5135,14 +5097,14 @@ } }, "node_modules/@smithy/middleware-content-length": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.2.3.tgz", - "integrity": "sha512-/atXLsT88GwKtfp5Jr0Ks1CSa4+lB+IgRnkNrrYP0h1wL4swHNb0YONEvTceNKNdZGJsye+W2HH8W7olbcPUeA==", + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.2.7.tgz", + "integrity": "sha512-GszfBfCcvt7kIbJ41LuNa5f0wvQCHhnGx/aDaZJCCT05Ld6x6U2s0xsc/0mBFONBZjQJp2U/0uSJ178OXOwbhg==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@smithy/protocol-http": "^5.3.3", - "@smithy/types": "^4.8.0", + "@smithy/protocol-http": "^5.3.7", + "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "engines": { @@ -5150,19 +5112,19 @@ } }, "node_modules/@smithy/middleware-endpoint": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.3.4.tgz", - "integrity": "sha512-/RJhpYkMOaUZoJEkddamGPPIYeKICKXOu/ojhn85dKDM0n5iDIhjvYAQLP3K5FPhgB203O3GpWzoK2OehEoIUw==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.4.1.tgz", + "integrity": "sha512-gpLspUAoe6f1M6H0u4cVuFzxZBrsGZmjx2O9SigurTx4PbntYa4AJ+o0G0oGm1L2oSX6oBhcGHwrfJHup2JnJg==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@smithy/core": "^3.17.0", - "@smithy/middleware-serde": "^4.2.3", - "@smithy/node-config-provider": "^4.3.3", - "@smithy/shared-ini-file-loader": "^4.3.3", - "@smithy/types": "^4.8.0", - "@smithy/url-parser": "^4.2.3", - "@smithy/util-middleware": "^4.2.3", + "@smithy/core": "^3.20.0", + "@smithy/middleware-serde": "^4.2.8", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/shared-ini-file-loader": "^4.4.2", + "@smithy/types": "^4.11.0", + "@smithy/url-parser": "^4.2.7", + "@smithy/util-middleware": "^4.2.7", "tslib": "^2.6.2" }, "engines": { @@ -5170,19 +5132,19 @@ } }, "node_modules/@smithy/middleware-retry": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.4.4.tgz", - "integrity": "sha512-vSgABQAkuUHRO03AhR2rWxVQ1un284lkBn+NFawzdahmzksAoOeVMnXXsuPViL4GlhRHXqFaMlc8Mj04OfQk1w==", + "version": "4.4.17", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.4.17.tgz", + "integrity": "sha512-MqbXK6Y9uq17h+4r0ogu/sBT6V/rdV+5NvYL7ZV444BKfQygYe8wAhDrVXagVebN6w2RE0Fm245l69mOsPGZzg==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@smithy/node-config-provider": "^4.3.3", - "@smithy/protocol-http": "^5.3.3", - "@smithy/service-error-classification": "^4.2.3", - "@smithy/smithy-client": "^4.9.0", - "@smithy/types": "^4.8.0", - "@smithy/util-middleware": "^4.2.3", - "@smithy/util-retry": "^4.2.3", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/protocol-http": "^5.3.7", + "@smithy/service-error-classification": "^4.2.7", + "@smithy/smithy-client": "^4.10.2", + "@smithy/types": "^4.11.0", + "@smithy/util-middleware": "^4.2.7", + "@smithy/util-retry": "^4.2.7", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" }, @@ -5191,14 +5153,14 @@ } }, "node_modules/@smithy/middleware-serde": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.2.3.tgz", - "integrity": "sha512-8g4NuUINpYccxiCXM5s1/V+uLtts8NcX4+sPEbvYQDZk4XoJfDpq5y2FQxfmUL89syoldpzNzA0R9nhzdtdKnQ==", + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.2.8.tgz", + "integrity": "sha512-8rDGYen5m5+NV9eHv9ry0sqm2gI6W7mc1VSFMtn6Igo25S507/HaOX9LTHAS2/J32VXD0xSzrY0H5FJtOMS4/w==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@smithy/protocol-http": "^5.3.3", - "@smithy/types": "^4.8.0", + "@smithy/protocol-http": "^5.3.7", + "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "engines": { @@ -5206,13 +5168,13 @@ } }, "node_modules/@smithy/middleware-stack": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.2.3.tgz", - "integrity": "sha512-iGuOJkH71faPNgOj/gWuEGS6xvQashpLwWB1HjHq1lNNiVfbiJLpZVbhddPuDbx9l4Cgl0vPLq5ltRfSaHfspA==", + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.2.7.tgz", + "integrity": "sha512-bsOT0rJ+HHlZd9crHoS37mt8qRRN/h9jRve1SXUhVbkRzu0QaNYZp1i1jha4n098tsvROjcwfLlfvcFuJSXEsw==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@smithy/types": "^4.8.0", + "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "engines": { @@ -5220,15 +5182,15 @@ } }, "node_modules/@smithy/node-config-provider": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.3.3.tgz", - "integrity": "sha512-NzI1eBpBSViOav8NVy1fqOlSfkLgkUjUTlohUSgAEhHaFWA3XJiLditvavIP7OpvTjDp5u2LhtlBhkBlEisMwA==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.3.7.tgz", + "integrity": "sha512-7r58wq8sdOcrwWe+klL9y3bc4GW1gnlfnFOuL7CXa7UzfhzhxKuzNdtqgzmTV+53lEp9NXh5hY/S4UgjLOzPfw==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@smithy/property-provider": "^4.2.3", - "@smithy/shared-ini-file-loader": "^4.3.3", - "@smithy/types": "^4.8.0", + "@smithy/property-provider": "^4.2.7", + "@smithy/shared-ini-file-loader": "^4.4.2", + "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "engines": { @@ -5236,16 +5198,16 @@ } }, "node_modules/@smithy/node-http-handler": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.4.2.tgz", - "integrity": "sha512-MHFvTjts24cjGo1byXqhXrbqm7uznFD/ESFx8npHMWTFQVdBZjrT1hKottmp69LBTRm/JQzP/sn1vPt0/r6AYQ==", + "version": "4.4.7", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.4.7.tgz", + "integrity": "sha512-NELpdmBOO6EpZtWgQiHjoShs1kmweaiNuETUpuup+cmm/xJYjT4eUjfhrXRP4jCOaAsS3c3yPsP3B+K+/fyPCQ==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@smithy/abort-controller": "^4.2.3", - "@smithy/protocol-http": "^5.3.3", - "@smithy/querystring-builder": "^4.2.3", - "@smithy/types": "^4.8.0", + "@smithy/abort-controller": "^4.2.7", + "@smithy/protocol-http": "^5.3.7", + "@smithy/querystring-builder": "^4.2.7", + "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "engines": { @@ -5253,13 +5215,13 @@ } }, "node_modules/@smithy/property-provider": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.2.3.tgz", - "integrity": "sha512-+1EZ+Y+njiefCohjlhyOcy1UNYjT+1PwGFHCxA/gYctjg3DQWAU19WigOXAco/Ql8hZokNehpzLd0/+3uCreqQ==", + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.2.7.tgz", + "integrity": "sha512-jmNYKe9MGGPoSl/D7JDDs1C8b3dC8f/w78LbaVfoTtWy4xAd5dfjaFG9c9PWPihY4ggMQNQSMtzU77CNgAJwmA==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@smithy/types": "^4.8.0", + "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "engines": { @@ -5267,13 +5229,13 @@ } }, "node_modules/@smithy/protocol-http": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.3.3.tgz", - "integrity": "sha512-Mn7f/1aN2/jecywDcRDvWWWJF4uwg/A0XjFMJtj72DsgHTByfjRltSqcT9NyE9RTdBSN6X1RSXrhn/YWQl8xlw==", + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.3.7.tgz", + "integrity": "sha512-1r07pb994I20dD/c2seaZhoCuNYm0rWrvBxhCQ70brNh11M5Ml2ew6qJVo0lclB3jMIXirD4s2XRXRe7QEi0xA==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@smithy/types": "^4.8.0", + "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "engines": { @@ -5281,13 +5243,13 @@ } }, "node_modules/@smithy/querystring-builder": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.2.3.tgz", - "integrity": "sha512-LOVCGCmwMahYUM/P0YnU/AlDQFjcu+gWbFJooC417QRB/lDJlWSn8qmPSDp+s4YVAHOgtgbNG4sR+SxF/VOcJQ==", + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.2.7.tgz", + "integrity": "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@smithy/types": "^4.8.0", + "@smithy/types": "^4.11.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" }, @@ -5296,13 +5258,13 @@ } }, "node_modules/@smithy/querystring-parser": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.2.3.tgz", - "integrity": "sha512-cYlSNHcTAX/wc1rpblli3aUlLMGgKZ/Oqn8hhjFASXMCXjIqeuQBei0cnq2JR8t4RtU9FpG6uyl6PxyArTiwKA==", + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.2.7.tgz", + "integrity": "sha512-3X5ZvzUHmlSTHAXFlswrS6EGt8fMSIxX/c3Rm1Pni3+wYWB6cjGocmRIoqcQF9nU5OgGmL0u7l9m44tSUpfj9w==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@smithy/types": "^4.8.0", + "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "engines": { @@ -5310,26 +5272,26 @@ } }, "node_modules/@smithy/service-error-classification": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.2.3.tgz", - "integrity": "sha512-NkxsAxFWwsPsQiwFG2MzJ/T7uIR6AQNh1SzcxSUnmmIqIQMlLRQDKhc17M7IYjiuBXhrQRjQTo3CxX+DobS93g==", + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.2.7.tgz", + "integrity": "sha512-YB7oCbukqEb2Dlh3340/8g8vNGbs/QsNNRms+gv3N2AtZz9/1vSBx6/6tpwQpZMEJFs7Uq8h4mmOn48ZZ72MkA==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@smithy/types": "^4.8.0" + "@smithy/types": "^4.11.0" }, "engines": { "node": ">=18.0.0" } }, "node_modules/@smithy/shared-ini-file-loader": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.3.3.tgz", - "integrity": "sha512-9f9Ixej0hFhroOK2TxZfUUDR13WVa8tQzhSzPDgXe5jGL3KmaM9s8XN7RQwqtEypI82q9KHnKS71CJ+q/1xLtQ==", + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.4.2.tgz", + "integrity": "sha512-M7iUUff/KwfNunmrgtqBfvZSzh3bmFgv/j/t1Y1dQ+8dNo34br1cqVEqy6v0mYEgi0DkGO7Xig0AnuOaEGVlcg==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@smithy/types": "^4.8.0", + "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "engines": { @@ -5337,17 +5299,17 @@ } }, "node_modules/@smithy/signature-v4": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.3.3.tgz", - "integrity": "sha512-CmSlUy+eEYbIEYN5N3vvQTRfqt0lJlQkaQUIf+oizu7BbDut0pozfDjBGecfcfWf7c62Yis4JIEgqQ/TCfodaA==", + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.3.7.tgz", + "integrity": "sha512-9oNUlqBlFZFOSdxgImA6X5GFuzE7V2H7VG/7E70cdLhidFbdtvxxt81EHgykGK5vq5D3FafH//X+Oy31j3CKOg==", "license": "Apache-2.0", "optional": true, "dependencies": { "@smithy/is-array-buffer": "^4.2.0", - "@smithy/protocol-http": "^5.3.3", - "@smithy/types": "^4.8.0", + "@smithy/protocol-http": "^5.3.7", + "@smithy/types": "^4.11.0", "@smithy/util-hex-encoding": "^4.2.0", - "@smithy/util-middleware": "^4.2.3", + "@smithy/util-middleware": "^4.2.7", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" @@ -5357,18 +5319,18 @@ } }, "node_modules/@smithy/smithy-client": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.9.0.tgz", - "integrity": "sha512-qz7RTd15GGdwJ3ZCeBKLDQuUQ88m+skh2hJwcpPm1VqLeKzgZvXf6SrNbxvx7uOqvvkjCMXqx3YB5PDJyk00ww==", + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.10.2.tgz", + "integrity": "sha512-D5z79xQWpgrGpAHb054Fn2CCTQZpog7JELbVQ6XAvXs5MNKWf28U9gzSBlJkOyMl9LA1TZEjRtwvGXfP0Sl90g==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@smithy/core": "^3.17.0", - "@smithy/middleware-endpoint": "^4.3.4", - "@smithy/middleware-stack": "^4.2.3", - "@smithy/protocol-http": "^5.3.3", - "@smithy/types": "^4.8.0", - "@smithy/util-stream": "^4.5.3", + "@smithy/core": "^3.20.0", + "@smithy/middleware-endpoint": "^4.4.1", + "@smithy/middleware-stack": "^4.2.7", + "@smithy/protocol-http": "^5.3.7", + "@smithy/types": "^4.11.0", + "@smithy/util-stream": "^4.5.8", "tslib": "^2.6.2" }, "engines": { @@ -5376,9 +5338,9 @@ } }, "node_modules/@smithy/types": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.8.0.tgz", - "integrity": "sha512-QpELEHLO8SsQVtqP+MkEgCYTFW0pleGozfs3cZ183ZBj9z3VC1CX1/wtFMK64p+5bhtZo41SeLK1rBRtd25nHQ==", + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.11.0.tgz", + "integrity": "sha512-mlrmL0DRDVe3mNrjTcVcZEgkFmufITfUAPBEA+AHYiIeYyJebso/He1qLbP3PssRe22KUzLRpQSdBPbXdgZ2VA==", "license": "Apache-2.0", "optional": true, "dependencies": { @@ -5389,14 +5351,14 @@ } }, "node_modules/@smithy/url-parser": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.2.3.tgz", - "integrity": "sha512-I066AigYvY3d9VlU3zG9XzZg1yT10aNqvCaBTw9EPgu5GrsEl1aUkcMvhkIXascYH1A8W0LQo3B1Kr1cJNcQEw==", + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.2.7.tgz", + "integrity": "sha512-/RLtVsRV4uY3qPWhBDsjwahAtt3x2IsMGnP5W1b2VZIe+qgCqkLxI1UOHDZp1Q1QSOrdOR32MF3Ph2JfWT1VHg==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@smithy/querystring-parser": "^4.2.3", - "@smithy/types": "^4.8.0", + "@smithy/querystring-parser": "^4.2.7", + "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "engines": { @@ -5472,15 +5434,15 @@ } }, "node_modules/@smithy/util-defaults-mode-browser": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.3.tgz", - "integrity": "sha512-vqHoybAuZXbFXZqgzquiUXtdY+UT/aU33sxa4GBPkiYklmR20LlCn+d3Wc3yA5ZM13gQ92SZe/D8xh6hkjx+IQ==", + "version": "4.3.16", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.16.tgz", + "integrity": "sha512-/eiSP3mzY3TsvUOYMeL4EqUX6fgUOj2eUOU4rMMgVbq67TiRLyxT7Xsjxq0bW3OwuzK009qOwF0L2OgJqperAQ==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@smithy/property-provider": "^4.2.3", - "@smithy/smithy-client": "^4.9.0", - "@smithy/types": "^4.8.0", + "@smithy/property-provider": "^4.2.7", + "@smithy/smithy-client": "^4.10.2", + "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "engines": { @@ -5488,18 +5450,18 @@ } }, "node_modules/@smithy/util-defaults-mode-node": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.4.tgz", - "integrity": "sha512-X5/xrPHedifo7hJUUWKlpxVb2oDOiqPUXlvsZv1EZSjILoutLiJyWva3coBpn00e/gPSpH8Rn2eIbgdwHQdW7Q==", + "version": "4.2.19", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.19.tgz", + "integrity": "sha512-3a4+4mhf6VycEJyHIQLypRbiwG6aJvbQAeRAVXydMmfweEPnLLabRbdyo/Pjw8Rew9vjsh5WCdhmDaHkQnhhhA==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@smithy/config-resolver": "^4.3.3", - "@smithy/credential-provider-imds": "^4.2.3", - "@smithy/node-config-provider": "^4.3.3", - "@smithy/property-provider": "^4.2.3", - "@smithy/smithy-client": "^4.9.0", - "@smithy/types": "^4.8.0", + "@smithy/config-resolver": "^4.4.5", + "@smithy/credential-provider-imds": "^4.2.7", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/property-provider": "^4.2.7", + "@smithy/smithy-client": "^4.10.2", + "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "engines": { @@ -5507,14 +5469,14 @@ } }, "node_modules/@smithy/util-endpoints": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.2.3.tgz", - "integrity": "sha512-aCfxUOVv0CzBIkU10TubdgKSx5uRvzH064kaiPEWfNIvKOtNpu642P4FP1hgOFkjQIkDObrfIDnKMKkeyrejvQ==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.2.7.tgz", + "integrity": "sha512-s4ILhyAvVqhMDYREeTS68R43B1V5aenV5q/V1QpRQJkCXib5BPRo4s7uNdzGtIKxaPHCfU/8YkvPAEvTpxgspg==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@smithy/node-config-provider": "^4.3.3", - "@smithy/types": "^4.8.0", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "engines": { @@ -5535,13 +5497,13 @@ } }, "node_modules/@smithy/util-middleware": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.2.3.tgz", - "integrity": "sha512-v5ObKlSe8PWUHCqEiX2fy1gNv6goiw6E5I/PN2aXg3Fb/hse0xeaAnSpXDiWl7x6LamVKq7senB+m5LOYHUAHw==", + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.2.7.tgz", + "integrity": "sha512-i1IkpbOae6NvIKsEeLLM9/2q4X+M90KV3oCFgWQI4q0Qz+yUZvsr+gZPdAEAtFhWQhAHpTsJO8DRJPuwVyln+w==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@smithy/types": "^4.8.0", + "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "engines": { @@ -5549,14 +5511,14 @@ } }, "node_modules/@smithy/util-retry": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.2.3.tgz", - "integrity": "sha512-lLPWnakjC0q9z+OtiXk+9RPQiYPNAovt2IXD3CP4LkOnd9NpUsxOjMx1SnoUVB7Orb7fZp67cQMtTBKMFDvOGg==", + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.2.7.tgz", + "integrity": "sha512-SvDdsQyF5CIASa4EYVT02LukPHVzAgUA4kMAuZ97QJc2BpAqZfA4PINB8/KOoCXEw9tsuv/jQjMeaHFvxdLNGg==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@smithy/service-error-classification": "^4.2.3", - "@smithy/types": "^4.8.0", + "@smithy/service-error-classification": "^4.2.7", + "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, "engines": { @@ -5564,15 +5526,15 @@ } }, "node_modules/@smithy/util-stream": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.5.3.tgz", - "integrity": "sha512-oZvn8a5bwwQBNYHT2eNo0EU8Kkby3jeIg1P2Lu9EQtqDxki1LIjGRJM6dJ5CZUig8QmLxWxqOKWvg3mVoOBs5A==", + "version": "4.5.8", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.5.8.tgz", + "integrity": "sha512-ZnnBhTapjM0YPGUSmOs0Mcg/Gg87k503qG4zU2v/+Js2Gu+daKOJMeqcQns8ajepY8tgzzfYxl6kQyZKml6O2w==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@smithy/fetch-http-handler": "^5.3.4", - "@smithy/node-http-handler": "^4.4.2", - "@smithy/types": "^4.8.0", + "@smithy/fetch-http-handler": "^5.3.8", + "@smithy/node-http-handler": "^4.4.7", + "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", @@ -5680,6 +5642,63 @@ "testcontainers": "^10.28.0" } }, + "node_modules/@testcontainers/postgresql": { + "version": "11.10.0", + "resolved": "https://registry.npmjs.org/@testcontainers/postgresql/-/postgresql-11.10.0.tgz", + "integrity": "sha512-d6QeN3KkXLJBdt0T6X3KKtdkHbaZdzCRPo133FSG8yOoGofQAYghtau39iUdeF9GAN8UTWZAxio40uYKBSV7xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "testcontainers": "^11.10.0" + } + }, + "node_modules/@testcontainers/postgresql/node_modules/docker-compose": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/docker-compose/-/docker-compose-1.3.0.tgz", + "integrity": "sha512-7Gevk/5eGD50+eMD+XDnFnOrruFkL0kSd7jEG4cjmqweDSUhB7i0g8is/nBdVpl+Bx338SqIB2GLKm32M+Vs6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "yaml": "^2.2.2" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/@testcontainers/postgresql/node_modules/testcontainers": { + "version": "11.10.0", + "resolved": "https://registry.npmjs.org/testcontainers/-/testcontainers-11.10.0.tgz", + "integrity": "sha512-8hwK2EnrOZfrHPpDC7CPe03q7H8Vv8j3aXdcmFFyNV8dzpBzgZYmqyDtduJ8YQ5kbzj+A+jUXMQ6zI8B5U3z+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@balena/dockerignore": "^1.0.2", + "@types/dockerode": "^3.3.47", + "archiver": "^7.0.1", + "async-lock": "^1.4.1", + "byline": "^5.0.0", + "debug": "^4.4.3", + "docker-compose": "^1.3.0", + "dockerode": "^4.0.9", + "get-port": "^7.1.0", + "proper-lockfile": "^4.1.2", + "properties-reader": "^2.3.0", + "ssh-remote-port-forward": "^1.0.4", + "tar-fs": "^3.1.1", + "tmp": "^0.2.5", + "undici": "^7.16.0" + } + }, + "node_modules/@testcontainers/postgresql/node_modules/undici": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.16.0.tgz", + "integrity": "sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, "node_modules/@testcontainers/rabbitmq": { "version": "10.28.0", "resolved": "https://registry.npmjs.org/@testcontainers/rabbitmq/-/rabbitmq-10.28.0.tgz", @@ -5757,9 +5776,9 @@ "license": "MIT" }, "node_modules/@types/cookies": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/@types/cookies/-/cookies-0.9.1.tgz", - "integrity": "sha512-E/DPgzifH4sM1UMadJMWd6mO2jOd4g1Ejwzx8/uRCDpJis1IrlyQEcGAYEomtAqRYmD5ORbNXMeI9U0RiVGZbg==", + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@types/cookies/-/cookies-0.9.2.tgz", + "integrity": "sha512-1AvkDdZM2dbyFybL4fxpuNCaWyv//0AwsuUk2DWeXyM1/5ZKm6W3z6mQi24RZ4l2ucY+bkSHzbDVpySqPGuV8A==", "license": "MIT", "dependencies": { "@types/connect": "*", @@ -5789,9 +5808,9 @@ } }, "node_modules/@types/dockerode": { - "version": "3.3.44", - "resolved": "https://registry.npmjs.org/@types/dockerode/-/dockerode-3.3.44.tgz", - "integrity": "sha512-fUpIHlsbYpxAJb285xx3vp7q5wf5mjqSn3cYwl/MhiM+DB99OdO5sOCPlO0PjO+TyOtphPs7tMVLU/RtOo/JjA==", + "version": "3.3.47", + "resolved": "https://registry.npmjs.org/@types/dockerode/-/dockerode-3.3.47.tgz", + "integrity": "sha512-ShM1mz7rCjdssXt7Xz0u1/R2BJC7piWa3SJpUBiVjCf2A3XNn4cP6pUVaD8bLanpPVVn4IKzJuw3dOvkJ8IbYw==", "dev": true, "license": "MIT", "dependencies": { @@ -5808,15 +5827,15 @@ "license": "MIT" }, "node_modules/@types/express": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.23.tgz", - "integrity": "sha512-Crp6WY9aTYP3qPi2wGDo9iUe/rceX01UMhnF1jmwDcKCFM6cx7YhGP/Mpr3y9AASpfHixIG0E6azCcL5OcDHsQ==", + "version": "4.17.25", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.25.tgz", + "integrity": "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==", "license": "MIT", "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", "@types/qs": "*", - "@types/serve-static": "*" + "@types/serve-static": "^1" } }, "node_modules/@types/express-serve-static-core": { @@ -5888,9 +5907,9 @@ } }, "node_modules/@types/koa-compose": { - "version": "3.2.8", - "resolved": "https://registry.npmjs.org/@types/koa-compose/-/koa-compose-3.2.8.tgz", - "integrity": "sha512-4Olc63RY+MKvxMwVknCUDhRQX1pFQoBZ/lXcRLP69PQkEpze/0cr8LNqJQe5NFb/b19DWi2a5bTi2VAlQzhJuA==", + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/@types/koa-compose/-/koa-compose-3.2.9.tgz", + "integrity": "sha512-BroAZ9FTvPiCy0Pi8tjD1OfJ7bgU1gQf0eR6e1Vm+JJATy9eKOG3hQMFtMciMawiSOVnLMdmUOC46s7HBhSTsA==", "license": "MIT", "dependencies": { "@types/koa": "*" @@ -5910,9 +5929,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "20.19.22", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.22.tgz", - "integrity": "sha512-hRnu+5qggKDSyWHlnmThnUqg62l29Aj/6vcYgUaSFL9oc7DVjeWEQN3PRgdSc6F8d9QRMWkf36CLMch1Do/+RQ==", + "version": "20.19.27", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.27.tgz", + "integrity": "sha512-N2clP5pJhB2YnZJ3PIHFk5RkygRX5WO/5f0WC08tp0wd+sv0rsJk3MqWn3CbNmT2J505a5336jaQj4ph1AdMug==", "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -5938,9 +5957,9 @@ "license": "MIT" }, "node_modules/@types/readable-stream": { - "version": "4.0.21", - "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.21.tgz", - "integrity": "sha512-19eKVv9tugr03IgfXlA9UVUVRbW6IuqRO5B92Dl4a6pT7K8uaGrNS0GkxiZD0BOk6PLuXl5FhWl//eX/pzYdTQ==", + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.23.tgz", + "integrity": "sha512-wwXrtQvbMHxCbBgjHaMGEmImFTQxxpfMOR/ZoQnXxB1woqkUbdLGFDgauo00Py9IudiaqSeiBiulSV9i6XIPig==", "license": "MIT", "dependencies": { "@types/node": "*" @@ -5970,18 +5989,18 @@ "license": "MIT" }, "node_modules/@types/send": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.0.tgz", - "integrity": "sha512-zBF6vZJn1IaMpg3xUF25VK3gd3l8zwE0ZLRX7dsQyQi+jp4E8mMDJNGDYnYse+bQhYwWERTxVwHpi3dMOq7RKQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/serve-static": { - "version": "1.15.9", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.9.tgz", - "integrity": "sha512-dOTIuqpWLyl3BBXU3maNQsS4A3zuuoYRNIvYSxxhebPfXg2mzWQEPne/nlJ37yOse6uGgR386uTpdsx4D0QZWA==", + "version": "1.15.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz", + "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==", "license": "MIT", "dependencies": { "@types/http-errors": "*", @@ -5990,9 +6009,9 @@ } }, "node_modules/@types/serve-static/node_modules/@types/send": { - "version": "0.17.5", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.5.tgz", - "integrity": "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==", + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz", + "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==", "license": "MIT", "dependencies": { "@types/mime": "^1", @@ -6010,9 +6029,9 @@ } }, "node_modules/@types/ssh2-streams": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/@types/ssh2-streams/-/ssh2-streams-0.1.12.tgz", - "integrity": "sha512-Sy8tpEmCce4Tq0oSOYdfqaBpA3hDM8SoxoFh5vzFsu2oL+znzGz8oVWW7xb4K920yYMUY+PIG31qZnFMfPWNCg==", + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/@types/ssh2-streams/-/ssh2-streams-0.1.13.tgz", + "integrity": "sha512-faHyY3brO9oLEA0QlcO8N2wT7R0+1sHWZvQ+y3rMLwdY1ZyS1z0W3t65j9PqT4HmQ6ALzNe7RZlNuCNE0wBSWA==", "dev": true, "license": "MIT", "dependencies": { @@ -6268,9 +6287,9 @@ } }, "node_modules/@typespec/ts-http-runtime": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.3.1.tgz", - "integrity": "sha512-SnbaqayTVFEA6/tYumdF0UmybY0KHyKwGPBXnyckFlrrKdhWFrL3a2HIPXHjht5ZOElKGcXfD2D63P36btb+ww==", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.3.2.tgz", + "integrity": "sha512-IlqQ/Gv22xUC1r/WQm4StLkYQmaaTsXAhUVsNE0+xiyf0yRFiH5++q78U3bw6bLKDCTmh0uqKB9eG9+Bt75Dkg==", "license": "MIT", "dependencies": { "http-proxy-agent": "^7.0.0", @@ -6428,9 +6447,9 @@ } }, "node_modules/@vvo/tzdb": { - "version": "6.187.0", - "resolved": "https://registry.npmjs.org/@vvo/tzdb/-/tzdb-6.187.0.tgz", - "integrity": "sha512-SkGZLQyHT3dYxv0HyUHX+h1lDwTMfJs/nXT6BrLdl1nXdpcCEeGJPGiVf/9uv8uD8mCeMok1MM5CcG67VoEypQ==", + "version": "6.198.0", + "resolved": "https://registry.npmjs.org/@vvo/tzdb/-/tzdb-6.198.0.tgz", + "integrity": "sha512-bNRWBhWYl0edVgyX6AYbhoCM2tk2lXJjGCyO2VDc2xn6Dw8dLd7WGj2DDXkVOkmOIQTNjEAcxrEpIzz5pWVwFg==", "license": "MIT" }, "node_modules/abbrev": { @@ -6738,9 +6757,9 @@ } }, "node_modules/archiver-utils/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==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", "dev": true, "license": "ISC", "dependencies": { @@ -7183,9 +7202,9 @@ "license": "MIT" }, "node_modules/bare-events": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.0.tgz", - "integrity": "sha512-AOhh6Bg5QmFIXdViHbMc2tLDsBIRxdkIaIddPslJF9Z5De3APBScuqGP2uThXnIpqFrgoxMNC6km7uXNIMLHXA==", + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz", + "integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==", "dev": true, "license": "Apache-2.0", "peerDependencies": { @@ -7198,9 +7217,9 @@ } }, "node_modules/bare-fs": { - "version": "4.4.11", - "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.4.11.tgz", - "integrity": "sha512-Bejmm9zRMvMTRoHS+2adgmXw1ANZnCNx+B5dgZpGwlP1E3x6Yuxea8RToddHUbWtVV0iUMWqsgZr8+jcgUI2SA==", + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.5.2.tgz", + "integrity": "sha512-veTnRzkb6aPHOvSKIOy60KzURfBdUflr5VReI+NSaPL6xf+XLdONQgZgpYvUuZLVQ8dCqxpBAudaOM1+KpAUxw==", "dev": true, "license": "Apache-2.0", "optional": true, @@ -7269,9 +7288,9 @@ } }, "node_modules/bare-url": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.3.0.tgz", - "integrity": "sha512-c+RCqMSZbkz97Mw1LWR0gcOqwK82oyYKfLoHJ8k13ybi1+I80ffdDzUy0TdAburdrR/kI0/VuN8YgEnJqX+Nyw==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.3.2.tgz", + "integrity": "sha512-ZMq4gd9ngV5aTMa5p9+UfY0b3skwhHELaDkhEHetMdX0LRkW9kzaym4oo/Eh+Ghm0CCDuMTsRIGM/ytUc1ZYmw==", "dev": true, "license": "Apache-2.0", "optional": true, @@ -7342,9 +7361,9 @@ } }, "node_modules/baseline-browser-mapping": { - "version": "2.8.31", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.31.tgz", - "integrity": "sha512-a28v2eWrrRWPpJSzxc+mKwm0ZtVx/G8SepdQZDArnXYU/XS+IF6mp8aB/4E+hH1tyGCoDo3KlUCdlSxGDsRkAw==", + "version": "2.9.11", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.11.tgz", + "integrity": "sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -7521,9 +7540,9 @@ } }, "node_modules/bowser": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.12.1.tgz", - "integrity": "sha512-z4rE2Gxh7tvshQ4hluIT7XcFrgLIQaw9X3A+kTTRdovCz5PMukm/0QC/BKSYPj3omF5Qfypn9O/c5kgpmvYUCw==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.13.1.tgz", + "integrity": "sha512-OHawaAbjwx6rqICCKgSG0SAnT05bzd7ppyKLVUITZpANBaaMFBAsaNkto3LoQ31tyFP5kNujE8Cdx85G9VzOkw==", "license": "MIT", "optional": true }, @@ -7550,9 +7569,9 @@ } }, "node_modules/browserslist": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.0.tgz", - "integrity": "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", "dev": true, "funding": [ { @@ -7570,11 +7589,11 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.8.25", - "caniuse-lite": "^1.0.30001754", - "electron-to-chromium": "^1.5.249", + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", "node-releases": "^2.0.27", - "update-browserslist-db": "^1.1.4" + "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" @@ -7642,9 +7661,9 @@ "license": "MIT" }, "node_modules/buildcheck": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/buildcheck/-/buildcheck-0.0.6.tgz", - "integrity": "sha512-8f9ZJCUXyT1M35Jx7MkBgmBMo3oHTTBIPLiY9xyL0pl3T5RwcPEY8cUHr5LBNfu/fk6c2T4DJZuVM/8ZZT2D2A==", + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/buildcheck/-/buildcheck-0.0.7.tgz", + "integrity": "sha512-lHblz4ahamxpTmnsk+MNTRWsjYKv965MwOrSJyeD588rR3Jcu7swE+0wN5F+PbL5cjgu/9ObkhfzEPuofEMwLA==", "dev": true, "optional": true, "engines": { @@ -7894,9 +7913,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001757", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001757.tgz", - "integrity": "sha512-r0nnL/I28Zi/yjk1el6ilj27tKcdjLsNqAOZr0yVjWPrSQyHgKI2INaEWw21bAQSv2LXRt1XuCS/GomNpWOxsQ==", + "version": "1.0.30001761", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001761.tgz", + "integrity": "sha512-JF9ptu1vP2coz98+5051jZ4PwQgd2ni8A+gYSN7EA7dPKIMf0pDlSUxhdmVOaV3/fYK5uWBkgSXJaRLr4+3A6g==", "dev": true, "funding": [ { @@ -8758,12 +8777,21 @@ } }, "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "dev": true, "license": "MIT" }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, "node_modules/data-view-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", @@ -8836,9 +8864,9 @@ } }, "node_modules/dayjs": { - "version": "1.11.18", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.18.tgz", - "integrity": "sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA==", + "version": "1.11.19", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz", + "integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==", "license": "MIT" }, "node_modules/debug": { @@ -8953,9 +8981,9 @@ } }, "node_modules/default-browser": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", - "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.4.0.tgz", + "integrity": "sha512-XDuvSq38Hr1MdN47EDvYtx3U0MTqpCEn+F6ft8z2vYDzMrvQhVp0ui9oQdqW3MvK3vqUETglt1tVGgjLuJ5izg==", "license": "MIT", "dependencies": { "bundle-name": "^4.1.0", @@ -8969,9 +8997,9 @@ } }, "node_modules/default-browser-id": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", - "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", "license": "MIT", "engines": { "node": ">=18" @@ -9189,9 +9217,9 @@ } }, "node_modules/dockerode/node_modules/@grpc/grpc-js": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.14.0.tgz", - "integrity": "sha512-N8Jx6PaYzcTRNzirReJCtADVoq4z7+1KQ4E70jTg/koQiMoUSN1kbNjPOqpPbhMFhfU1/l7ixspPl8dNY+FoUg==", + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.14.3.tgz", + "integrity": "sha512-Iq8QQQ/7X3Sac15oB6p0FmUg/klxQvXLeileoqrTRGJYLV+/9tubbr9ipz0GKHjmXVsgFPo/+W+2cA8eNcR+XA==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -9448,9 +9476,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.261", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.261.tgz", - "integrity": "sha512-cmyHEWFqEt3ICUNF93ShneOF47DHoSDbLb7E/AonsWcbzg95N+kPXeLNfkdzgTT/vEUcoW76fxbLBkeYtfoM8A==", + "version": "1.5.267", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", + "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", "dev": true, "license": "ISC" }, @@ -9668,9 +9696,9 @@ } }, "node_modules/es-abstract": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", - "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz", + "integrity": "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==", "dev": true, "license": "MIT", "dependencies": { @@ -10035,22 +10063,6 @@ "concat-map": "0.0.1" } }, - "node_modules/eslint/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -10064,19 +10076,6 @@ "node": "*" } }, - "node_modules/eslint/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/esm": { "version": "3.2.25", "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", @@ -10477,6 +10476,29 @@ "node": ">=0.4.0" } }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -10663,9 +10685,9 @@ } }, "node_modules/form-data": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", - "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", "license": "MIT", "dependencies": { "asynckit": "^0.4.0", @@ -10684,6 +10706,27 @@ "integrity": "sha512-EFRDrsMm/kyqbTQocNvRXMLjc7Es2Vk+IQFx/YW7hkUH1eBl4J1fqiP34l74Yt0pFLCNpc06fkbVk00008mzjg==", "license": "MIT" }, + "node_modules/formdata-node": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-6.0.3.tgz", + "integrity": "sha512-8e1++BCiTzUno9v5IZ2J6bv4RU+3UKDmqWUQD0MIMVCd9AdhWkO1gw57oo1mNEX1dMq2EGI+FbWz4B92pscSQg==", + "license": "MIT", + "engines": { + "node": ">= 18" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -11313,6 +11356,22 @@ "which": "bin/which" } }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/globalthis": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", @@ -11791,7 +11850,6 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "devOptional": true, "license": "MIT", "engines": { "node": ">=0.8.19" @@ -11863,9 +11921,9 @@ } }, "node_modules/ip-address": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz", - "integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", + "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", "license": "MIT", "engines": { "node": ">= 12" @@ -12559,9 +12617,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "license": "MIT", "dependencies": { @@ -12683,12 +12741,12 @@ } }, "node_modules/jsonwebtoken": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", - "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", + "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==", "license": "MIT", "dependencies": { - "jws": "^3.2.2", + "jws": "^4.0.1", "lodash.includes": "^4.3.0", "lodash.isboolean": "^3.0.3", "lodash.isinteger": "^4.0.4", @@ -12711,9 +12769,9 @@ "license": "MIT" }, "node_modules/jwa": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", - "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", "license": "MIT", "dependencies": { "buffer-equal-constant-time": "^1.0.1", @@ -12722,12 +12780,12 @@ } }, "node_modules/jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", "license": "MIT", "dependencies": { - "jwa": "^1.4.1", + "jwa": "^2.0.1", "safe-buffer": "^5.0.1" } }, @@ -12954,9 +13012,9 @@ "license": "MIT" }, "node_modules/liquidjs": { - "version": "10.22.0", - "resolved": "https://registry.npmjs.org/liquidjs/-/liquidjs-10.22.0.tgz", - "integrity": "sha512-SGBYxl7U7vqmmAQdP/PTP3P3q11f99xUjdtxVICqNQqPecl+JIMCsTshDObGzicHaAqWAnPW0o25a9hDaJxOng==", + "version": "10.24.0", + "resolved": "https://registry.npmjs.org/liquidjs/-/liquidjs-10.24.0.tgz", + "integrity": "sha512-TAUNAdgwaAXjjcUFuYVJm9kOVH7zc0mTKxsG9t9Lu4qdWjB2BEblyVIYpjWcmJLMGgiYqnGNJjpNMHx0gp/46A==", "license": "MIT", "dependencies": { "commander": "^10.0.0" @@ -12989,6 +13047,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/locko": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/locko/-/locko-1.1.0.tgz", + "integrity": "sha512-pYB2dzRY93fJkg2RIl41AMNgTQftEjyTK9vlPrGOJvuGQsOjb267VJBw15BjiN3RBd1oBoKkOu9E2dRdFKIfAA==", + "license": "MIT" + }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -13109,9 +13173,9 @@ } }, "node_modules/lru.min": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.2.tgz", - "integrity": "sha512-Nv9KddBcQSlQopmBHXSsZVY5xsdlZkdH/Iey0BlcBYggMd4two7cZnKOK9vmy3nY0O5RGH99z1PCeTpPqszUYg==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.3.tgz", + "integrity": "sha512-Lkk/vx6ak3rYkRR0Nhu4lFUT2VDnQSxBe8Hbl7f36358p6ow8Bnvr8lrLt98H8J1aGxfhbX4Fs5tYg2+FTwr5Q==", "license": "MIT", "engines": { "bun": ">=1.0.0", @@ -13540,7 +13604,6 @@ "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", "license": "ISC", - "optional": true, "dependencies": { "minipass": "^3.0.0" }, @@ -13553,7 +13616,6 @@ "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", "license": "ISC", - "optional": true, "dependencies": { "minipass": "^3.0.0" }, @@ -13812,30 +13874,21 @@ } }, "node_modules/named-placeholders": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz", - "integrity": "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.6.tgz", + "integrity": "sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==", "license": "MIT", "dependencies": { - "lru-cache": "^7.14.1" + "lru.min": "^1.1.0" }, "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/named-placeholders/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "license": "ISC", - "engines": { - "node": ">=12" + "node": ">=8.0.0" } }, "node_modules/nan": { - "version": "2.23.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.23.0.tgz", - "integrity": "sha512-1UxuyYGdoQHcGg87Lkqm3FzefucTa0NAiOcuRsDmysep3c1LVCRK2krrUDafMWtjSG04htvAmvg96+SDknOmgQ==", + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.24.0.tgz", + "integrity": "sha512-Vpf9qnVW1RaDkoNKFUvfxqAbtI8ncb8OJlqZ9wwpXzWPEsvsB1nvdUi6oYrHIkQ1Y/tMDnr1h4nczS0VB9Xykg==", "dev": true, "license": "MIT", "optional": true @@ -13905,6 +13958,26 @@ "command-exists": "^1.2.9" } }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", @@ -13925,6 +13998,211 @@ } } }, + "node_modules/node-fetch-cache": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/node-fetch-cache/-/node-fetch-cache-5.1.0.tgz", + "integrity": "sha512-4j3rRHNGIKGX7VzXSrBT0bh7+wFuyJv1DxCfCLDHsnDahJWoD9lXe3BzL3BJg/GEIJiM7KIvqVs3byW1GFtRsQ==", + "license": "MIT", + "dependencies": { + "cacache": "^20.0.1", + "formdata-node": "^6.0.3", + "locko": "^1.1.0", + "node-fetch": "3.3.2" + }, + "engines": { + "node": ">=18.19.0" + } + }, + "node_modules/node-fetch-cache/node_modules/@npmcli/fs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-5.0.0.tgz", + "integrity": "sha512-7OsC1gNORBEawOa5+j2pXN9vsicaIOH5cPXxoR6fJOmH6/EXpJB2CajXOu1fPRFun2m1lktEFX11+P89hqO/og==", + "license": "ISC", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/node-fetch-cache/node_modules/cacache": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-20.0.3.tgz", + "integrity": "sha512-3pUp4e8hv07k1QlijZu6Kn7c9+ZpWWk4j3F8N3xPuCExULobqJydKYOTj1FTq58srkJsXvO7LbGAH4C0ZU3WGw==", + "license": "ISC", + "dependencies": { + "@npmcli/fs": "^5.0.0", + "fs-minipass": "^3.0.0", + "glob": "^13.0.0", + "lru-cache": "^11.1.0", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^7.0.2", + "ssri": "^13.0.0", + "unique-filename": "^5.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/node-fetch-cache/node_modules/fs-minipass": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/node-fetch-cache/node_modules/glob": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.0.tgz", + "integrity": "sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.1.1", + "minipass": "^7.1.2", + "path-scurry": "^2.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-fetch-cache/node_modules/lru-cache": { + "version": "11.2.4", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", + "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/node-fetch-cache/node_modules/minimatch": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", + "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/brace-expansion": "^5.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-fetch-cache/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/node-fetch-cache/node_modules/minipass-collect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", + "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/node-fetch-cache/node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/node-fetch-cache/node_modules/p-map": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", + "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/node-fetch-cache/node_modules/path-scurry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.1.tgz", + "integrity": "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-fetch-cache/node_modules/ssri": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-13.0.0.tgz", + "integrity": "sha512-yizwGBpbCn4YomB2lzhZqrHLJoqFGXihNbib3ozhqF/cIp5ue+xSmOQrjNasEE62hFxsCcg/V/z23t4n8jMEng==", + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/node-fetch-cache/node_modules/unique-filename": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-5.0.0.tgz", + "integrity": "sha512-2RaJTAvAb4owyjllTfXzFClJ7WsGxlykkPvCr9pA//LD9goVq+m4PPAeBgNodGZ7nSrntT/auWpJ6Y5IFXcfjg==", + "license": "ISC", + "dependencies": { + "unique-slug": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/node-fetch-cache/node_modules/unique-slug": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-6.0.0.tgz", + "integrity": "sha512-4Lup7Ezn8W3d52/xBhZBVdx323ckxa7DEvd9kPQHppTkLoJXw6ltrBCyj5pnrxj0qKDxYMJ56CoxNuFCscdTiw==", + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, "node_modules/node-fetch/node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -14120,9 +14398,9 @@ } }, "node_modules/nostr-tools": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/nostr-tools/-/nostr-tools-2.17.0.tgz", - "integrity": "sha512-lrvHM7cSaGhz7F0YuBvgHMoU2s8/KuThihDoOYk8w5gpVHTy0DeUCAgCN8uLGeuSl5MAWekJr9Dkfo5HClqO9w==", + "version": "2.19.4", + "resolved": "https://registry.npmjs.org/nostr-tools/-/nostr-tools-2.19.4.tgz", + "integrity": "sha512-qVLfoTpZegNYRJo5j+Oi6RPu0AwLP6jcvzcB3ySMnIT5DrAGNXfs5HNBspB/2HiGfH3GY+v6yXkTtcKSBQZwSg==", "license": "Unlicense", "dependencies": { "@noble/ciphers": "^0.5.1", @@ -14253,9 +14531,9 @@ } }, "node_modules/oidc-token-hash": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.1.1.tgz", - "integrity": "sha512-D7EmwxJV6DsEB6vOFLrBM2OzsVgQzgPWyHlV2OOAVj772n+WTXpudC9e9u5BVKQnYwaD30Ivhi9b+4UeBcGu9g==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.2.0.tgz", + "integrity": "sha512-6gj2m8cJZ+iSW8bm0FXdGF0YhIQbKrfP4yWTNzxc31U6MOjfEmB1rHvlYvxI1B7t7BCi1F2vYTT6YhtQRG4hxw==", "license": "MIT", "engines": { "node": "^10.13.0 || >=12.0.0" @@ -14957,9 +15235,9 @@ } }, "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==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz", + "integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -15991,12 +16269,12 @@ "license": "MIT" }, "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==", + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", "license": "MIT", "dependencies": { - "is-core-module": "^2.16.0", + "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -16098,9 +16376,9 @@ } }, "node_modules/rollup": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.5.tgz", - "integrity": "sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==", + "version": "4.53.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.5.tgz", + "integrity": "sha512-iTNAbFSlRpcHeeWu73ywU/8KuU/LZmNCSxp6fjQkJBD3ivUb8tpDrXhIxEzA05HlYMEwmtaUnb3RP+YNv162OQ==", "dev": true, "license": "MIT", "dependencies": { @@ -16114,28 +16392,28 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.52.5", - "@rollup/rollup-android-arm64": "4.52.5", - "@rollup/rollup-darwin-arm64": "4.52.5", - "@rollup/rollup-darwin-x64": "4.52.5", - "@rollup/rollup-freebsd-arm64": "4.52.5", - "@rollup/rollup-freebsd-x64": "4.52.5", - "@rollup/rollup-linux-arm-gnueabihf": "4.52.5", - "@rollup/rollup-linux-arm-musleabihf": "4.52.5", - "@rollup/rollup-linux-arm64-gnu": "4.52.5", - "@rollup/rollup-linux-arm64-musl": "4.52.5", - "@rollup/rollup-linux-loong64-gnu": "4.52.5", - "@rollup/rollup-linux-ppc64-gnu": "4.52.5", - "@rollup/rollup-linux-riscv64-gnu": "4.52.5", - "@rollup/rollup-linux-riscv64-musl": "4.52.5", - "@rollup/rollup-linux-s390x-gnu": "4.52.5", - "@rollup/rollup-linux-x64-gnu": "4.52.5", - "@rollup/rollup-linux-x64-musl": "4.52.5", - "@rollup/rollup-openharmony-arm64": "4.52.5", - "@rollup/rollup-win32-arm64-msvc": "4.52.5", - "@rollup/rollup-win32-ia32-msvc": "4.52.5", - "@rollup/rollup-win32-x64-gnu": "4.52.5", - "@rollup/rollup-win32-x64-msvc": "4.52.5", + "@rollup/rollup-android-arm-eabi": "4.53.5", + "@rollup/rollup-android-arm64": "4.53.5", + "@rollup/rollup-darwin-arm64": "4.53.5", + "@rollup/rollup-darwin-x64": "4.53.5", + "@rollup/rollup-freebsd-arm64": "4.53.5", + "@rollup/rollup-freebsd-x64": "4.53.5", + "@rollup/rollup-linux-arm-gnueabihf": "4.53.5", + "@rollup/rollup-linux-arm-musleabihf": "4.53.5", + "@rollup/rollup-linux-arm64-gnu": "4.53.5", + "@rollup/rollup-linux-arm64-musl": "4.53.5", + "@rollup/rollup-linux-loong64-gnu": "4.53.5", + "@rollup/rollup-linux-ppc64-gnu": "4.53.5", + "@rollup/rollup-linux-riscv64-gnu": "4.53.5", + "@rollup/rollup-linux-riscv64-musl": "4.53.5", + "@rollup/rollup-linux-s390x-gnu": "4.53.5", + "@rollup/rollup-linux-x64-gnu": "4.53.5", + "@rollup/rollup-linux-x64-musl": "4.53.5", + "@rollup/rollup-openharmony-arm64": "4.53.5", + "@rollup/rollup-win32-arm64-msvc": "4.53.5", + "@rollup/rollup-win32-ia32-msvc": "4.53.5", + "@rollup/rollup-win32-x64-gnu": "4.53.5", + "@rollup/rollup-win32-x64-msvc": "4.53.5", "fsevents": "~2.3.2" } }, @@ -16343,10 +16621,10 @@ } }, "node_modules/sax": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", - "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", - "license": "ISC" + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.3.tgz", + "integrity": "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==", + "license": "BlueOak-1.0.0" }, "node_modules/sb-promise-queue": { "version": "2.1.1", @@ -17388,9 +17666,9 @@ } }, "node_modules/strnum": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.1.tgz", - "integrity": "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.2.tgz", + "integrity": "sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ==", "funding": [ { "type": "github", @@ -17702,9 +17980,9 @@ } }, "node_modules/tedious": { - "version": "18.6.1", - "resolved": "https://registry.npmjs.org/tedious/-/tedious-18.6.1.tgz", - "integrity": "sha512-9AvErXXQTd6l7TDd5EmM+nxbOGyhnmdbp/8c3pw+tjaiSXW9usME90ET/CRG1LN1Y9tPMtz/p83z4Q97B4DDpw==", + "version": "18.6.2", + "resolved": "https://registry.npmjs.org/tedious/-/tedious-18.6.2.tgz", + "integrity": "sha512-g7jC56o3MzLkE3lHkaFe2ZdOVFBahq5bsB60/M4NYUbocw/MCrS89IOEQUFr+ba6pb8ZHczZ/VqCyYeYq0xBAg==", "license": "MIT", "dependencies": { "@azure/core-auth": "^1.7.2", @@ -17723,9 +18001,9 @@ } }, "node_modules/tedious/node_modules/bl": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/bl/-/bl-6.1.4.tgz", - "integrity": "sha512-ZV/9asSuknOExbM/zPPA8z00lc1ihPKWaStHkkQrxHNeYx+yY+TmF+v80dpv2G0mv3HVXBu7ryoAsxbFFhf4eg==", + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/bl/-/bl-6.1.6.tgz", + "integrity": "sha512-jLsPgN/YSvPUg9UX0Kd73CXpm2Psg9FxMeCSXnk3WBO3CMT10JMwijubhGfHCnFu6TPn1ei3b975dxv7K2pWVg==", "license": "MIT", "dependencies": { "@types/readable-stream": "^4.0.0", @@ -17803,6 +18081,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/tempy/node_modules/type-fest": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", + "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/terser": { "version": "5.15.1", "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz", @@ -17977,6 +18268,24 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/tldts": { + "version": "7.0.19", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.19.tgz", + "integrity": "sha512-8PWx8tvC4jDB39BQw1m4x8y5MH1BcQ5xHeL2n7UVFulMPH/3Q0uiamahFJ3lXA0zO2SUyRXuVVbWSDmstlt9YA==", + "license": "MIT", + "dependencies": { + "tldts-core": "^7.0.19" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "7.0.19", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.19.tgz", + "integrity": "sha512-lJX2dEWx0SGH4O6p+7FPwYmJ/bu1JbcGJ8RLaG9b7liIgZ85itUVEPbMtWRVrde/0fnDPEPHW10ZsKW3kVsE9A==", + "license": "MIT" + }, "node_modules/tmp": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", @@ -18120,9 +18429,9 @@ } }, "node_modules/type-fest": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", - "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { @@ -18401,9 +18710,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", - "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "dev": true, "funding": [ { @@ -18528,9 +18837,9 @@ } }, "node_modules/vite": { - "version": "5.4.20", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.20.tgz", - "integrity": "sha512-j3lYzGC3P+B5Yfy/pfKNgVEg4+UtcIJcVRt2cDjIOmhLourAqPqf8P7acgxeiSgUB7E3p2P8/3gNIgDLpwzs4g==", + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", "dev": true, "license": "MIT", "dependencies": { @@ -18603,17 +18912,17 @@ } }, "node_modules/vite-plugin-pwa": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/vite-plugin-pwa/-/vite-plugin-pwa-1.1.0.tgz", - "integrity": "sha512-VsSpdubPzXhHWVINcSx6uHRMpOHVHQcHsef1QgkOlEoaIDAlssFEW88LBq1a59BuokAhsh2kUDJbaX1bZv4Bjw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/vite-plugin-pwa/-/vite-plugin-pwa-1.2.0.tgz", + "integrity": "sha512-a2xld+SJshT9Lgcv8Ji4+srFJL4k/1bVbd1x06JIkvecpQkwkvCncD1+gSzcdm3s+owWLpMJerG3aN5jupJEVw==", "dev": true, "license": "MIT", "dependencies": { "debug": "^4.3.6", "pretty-bytes": "^6.1.1", "tinyglobby": "^0.2.10", - "workbox-build": "^7.3.0", - "workbox-window": "^7.3.0" + "workbox-build": "^7.4.0", + "workbox-window": "^7.4.0" }, "engines": { "node": ">=16.0.0" @@ -18624,8 +18933,8 @@ "peerDependencies": { "@vite-pwa/assets-generator": "^1.0.0", "vite": "^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", - "workbox-build": "^7.3.0", - "workbox-window": "^7.3.0" + "workbox-build": "^7.4.0", + "workbox-window": "^7.4.0" }, "peerDependenciesMeta": { "@vite-pwa/assets-generator": { @@ -18889,9 +19198,9 @@ } }, "node_modules/wait-on/node_modules/axios": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz", - "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz", + "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", "dev": true, "license": "MIT", "dependencies": { @@ -18929,25 +19238,13 @@ "node": ">= 16" } }, - "node_modules/web-push/node_modules/jwa": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", - "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", "license": "MIT", - "dependencies": { - "buffer-equal-constant-time": "^1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/web-push/node_modules/jws": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", - "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", - "license": "MIT", - "dependencies": { - "jwa": "^2.0.0", - "safe-buffer": "^5.0.1" + "engines": { + "node": ">= 8" } }, "node_modules/webidl-conversions": { @@ -19275,11 +19572,11 @@ "license": "MIT" }, "node_modules/workbox-build/node_modules/lru-cache": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz", - "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==", + "version": "11.2.4", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", + "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "engines": { "node": "20 || >=22" } @@ -19739,9 +20036,9 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", - "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", + "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", "dev": true, "license": "ISC", "bin": { @@ -19749,6 +20046,9 @@ }, "engines": { "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" } }, "node_modules/yargs": { diff --git a/package.json b/package.json index 343de9352..04247d031 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "uptime-kuma", - "version": "2.0.2", + "version": "2.1.0-beta.0", "license": "MIT", "repository": { "type": "git", @@ -121,6 +121,8 @@ "nanoid": "~3.3.4", "net-snmp": "^3.11.2", "node-cloudflared-tunnel": "~1.0.9", + "node-radius-utils": "~1.2.0", + "node-fetch-cache": "^5.1.0", "nodemailer": "~6.9.13", "nostr-tools": "^2.10.4", "notp": "~2.0.3", @@ -135,7 +137,6 @@ "protobufjs": "~7.2.4", "qs": "~6.10.4", "radius": "~1.1.4", - "node-radius-utils": "~1.2.0", "redbean-node": "~0.3.0", "redis": "~5.9.0", "semver": "~7.5.4", @@ -146,6 +147,7 @@ "tar": "~6.2.1", "tcp-ping": "~0.1.1", "thirty-two": "~1.0.2", + "tldts": "^7.0.19", "tough-cookie": "~4.1.3", "web-push": "^3.6.7", "ws": "^8.13.0" @@ -159,6 +161,7 @@ "@playwright/test": "~1.39.0", "@popperjs/core": "~2.10.2", "@testcontainers/hivemq": "^10.13.1", + "@testcontainers/postgresql": "^11.9.0", "@testcontainers/rabbitmq": "^10.13.2", "@types/bootstrap": "~5.1.9", "@types/node": "^20.8.6", diff --git a/server/client.js b/server/client.js index 72f0a4e8e..4076242c0 100644 --- a/server/client.js +++ b/server/client.js @@ -142,27 +142,23 @@ async function sendAPIKeyList(socket) { * @returns {Promise} */ async function sendInfo(socket, hideVersion = false) { - let version; - let latestVersion; - let isContainer; - let dbType; - - if (!hideVersion) { - version = checkVersion.version; - latestVersion = checkVersion.latestVersion; - isContainer = (process.env.UPTIME_KUMA_IS_CONTAINER === "1"); - dbType = Database.dbConfig.type; - } - - socket.emit("info", { - version, - latestVersion, - isContainer, - dbType, + const info = { primaryBaseURL: await setting("primaryBaseURL"), serverTimezone: await server.getTimezone(), serverTimezoneOffset: server.getTimezoneOffset(), - }); + }; + if (!hideVersion) { + info.version = checkVersion.version; + info.latestVersion = checkVersion.latestVersion; + info.isContainer = (process.env.UPTIME_KUMA_IS_CONTAINER === "1"); + info.dbType = Database.dbConfig.type; + info.runtime = { + platform: process.platform, // linux or win32 + arch: process.arch, // x86 or arm + }; + } + + socket.emit("info", info); } /** diff --git a/server/database.js b/server/database.js index d22ceb29b..51785a04b 100644 --- a/server/database.js +++ b/server/database.js @@ -223,9 +223,24 @@ class Database { let config = {}; + let parsedMaxPoolConnections = parseInt(process.env.UPTIME_KUMA_DB_POOL_MAX_CONNECTIONS); + + if (!process.env.UPTIME_KUMA_DB_POOL_MAX_CONNECTIONS) { + parsedMaxPoolConnections = 10; + } else if (Number.isNaN(parsedMaxPoolConnections)) { + log.warn("db", "Max database connections defaulted to 10 because UPTIME_KUMA_DB_POOL_MAX_CONNECTIONS was invalid."); + parsedMaxPoolConnections = 10; + } else if (parsedMaxPoolConnections < 1) { + log.warn("db", "Max database connections defaulted to 10 because UPTIME_KUMA_DB_POOL_MAX_CONNECTIONS was less than 1."); + parsedMaxPoolConnections = 10; + } else if (parsedMaxPoolConnections > 100) { + log.warn("db", "Max database connections capped to 100 because Mysql/Mariadb connections are heavy. consider using a proxy like ProxySQL or MaxScale."); + parsedMaxPoolConnections = 100; + } + let mariadbPoolConfig = { min: 0, - max: 10, + max: parsedMaxPoolConnections, idleTimeoutMillis: 30000, }; @@ -811,9 +826,7 @@ class Database { await Settings.set("migrateAggregateTableState", "migrating"); let progressPercent = 0; - let part = 100 / monitors.length; - let i = 1; - for (let monitor of monitors) { + for (const [ i, monitor ] of monitors.entries()) { // Get a list of unique dates from the heartbeat table, using raw sql let dates = await R.getAll(` SELECT DISTINCT DATE(time) AS date @@ -824,7 +837,7 @@ class Database { monitor.monitor_id ]); - for (let date of dates) { + for (const [ dateIndex, date ] of dates.entries()) { // New Uptime Calculator let calculator = new UptimeCalculator(); calculator.monitorID = monitor.monitor_id; @@ -840,7 +853,7 @@ class Database { `, [ monitor.monitor_id, date.date ]); if (heartbeats.length > 0) { - msg = `[DON'T STOP] Migrating monitor data ${monitor.monitor_id} - ${date.date} [${progressPercent.toFixed(2)}%][${i}/${monitors.length}]`; + msg = `[DON'T STOP] Migrating monitor ${monitor.monitor_id}s' (${i + 1} of ${monitors.length} total) data - ${date.date} - total migration progress ${progressPercent.toFixed(2)}%`; log.info("db", msg); migrationServer?.update(msg); } @@ -849,15 +862,14 @@ class Database { await calculator.update(heartbeat.status, parseFloat(heartbeat.ping), dayjs(heartbeat.time)); } - progressPercent += (Math.round(part / dates.length * 100) / 100); + // Calculate progress: (current_monitor_index + relative_date_progress) / total_monitors + progressPercent = (i + (dateIndex + 1) / dates.length) / monitors.length * 100; // Lazy to fix the floating point issue, it is acceptable since it is just a progress bar if (progressPercent > 100) { progressPercent = 100; } } - - i++; } msg = "Clearing non-important heartbeats"; diff --git a/server/model/domain_expiry.js b/server/model/domain_expiry.js new file mode 100644 index 000000000..b796a81d1 --- /dev/null +++ b/server/model/domain_expiry.js @@ -0,0 +1,270 @@ +const { BeanModel } = require("redbean-node/dist/bean-model"); +const { R } = require("redbean-node"); +const { log } = require("../../src/util"); +const { parse: parseTld } = require("tldts"); +const { getDaysRemaining, getDaysBetween, setting, setSetting } = require("../util-server"); +const { Notification } = require("../notification"); +const { default: NodeFetchCache, MemoryCache } = require("node-fetch-cache"); + +const TABLE = "domain_expiry"; +const urlTypes = [ "websocket-upgrade", "http", "keyword", "json-query", "real-browser" ]; +const excludeTypes = [ "docker", "group", "push", "manual", "rabbitmq", "redis" ]; + +const cachedFetch = process.env.NODE_ENV ? NodeFetchCache.create({ + // cache for 8h + cache: new MemoryCache({ ttl: 1000 * 60 * 60 * 8 }) +}) : fetch; + +/** + * Find the RDAP server for a given TLD + * @param {string} tld TLD + * @returns {Promise} First RDAP server found + */ +async function getRdapServer(tld) { + let rdapList; + try { + const res = await cachedFetch("https://data.iana.org/rdap/dns.json"); + rdapList = await res.json(); + } catch (error) { + log.debug("rdap", error); + return null; + } + + for (const service of rdapList["services"]) { + const [ tlds, urls ] = service; + if (tlds.includes(tld)) { + return urls[0]; + } + } + return null; +} + +/** + * Request RDAP server to retrieve the expiry date of a domain + * @param {string} domain Domain to retrieve the expiry date from + * @returns {Promise<(Date|null)>} Expiry date from RDAP server + */ +async function getRdapDomainExpiryDate(domain) { + const tld = DomainExpiry.parseTld(domain).publicSuffix; + const rdapServer = await getRdapServer(tld); + if (rdapServer === null) { + log.warn("rdap", `No RDAP server found, TLD ${tld} not supported.`); + return null; + } + const url = `${rdapServer}domain/${domain}`; + + let rdapInfos; + try { + const res = await fetch(url); + if (res.status !== 200) { + return null; + } + rdapInfos = await res.json(); + } catch { + log.warn("rdap", "Not able to get expiry date from RDAP"); + return null; + } + + if (rdapInfos["events"] === undefined) { + return null; + } + for (const event of rdapInfos["events"]) { + if (event["eventAction"] === "expiration") { + return new Date(event["eventDate"]); + } + } + return null; +} + +/** + * Send a certificate notification when domain expires in less than target days + * @param {string} domain Domain we monitor + * @param {number} daysRemaining Number of days remaining on certificate + * @param {number} targetDays Number of days to alert after + * @param {LooseObject[]} notificationList List of notification providers + * @returns {Promise} + */ +async function sendDomainNotificationByTargetDays(domain, daysRemaining, targetDays, notificationList) { + let sent = false; + log.debug("domain", `Send domain expiry notification for ${targetDays} deadline.`); + + for (let notification of notificationList) { + try { + log.debug("domain", `Sending to ${notification.name}`); + await Notification.send( + JSON.parse(notification.config), + `Domain name ${domain} will expire in ${daysRemaining} days` + ); + sent = true; + } catch (e) { + log.error("domain", `Cannot send domain notification to ${notification.name}`); + log.error("domain", e); + } + } + + return sent; +} + +class DomainExpiry extends BeanModel { + /** + * @param {string} domain Domain name + * @returns {Promise} Domain bean + */ + static async findByName(domain) { + return R.findOne(TABLE, "domain = ?", [ domain ]); + } + + /** + * @param {string} domain Domain name + * @returns {DomainExpiry} Domain bean + */ + static createByName(domain) { + const d = R.dispense(TABLE); + d.domain = domain; + return d; + } + + static parseTld = parseTld; + + /** + * @returns {(object)} parsed domain components + */ + parseName() { + return parseTld(this.domain); + } + + /** + * @returns {(null|object)} parsed domain tld + */ + get tld() { + return this.parseName().publicSuffix; + } + + /** + * @param {Monitor} monitor Monitor object + * @returns {Promise} Domain expiry bean + */ + static async forMonitor(monitor) { + const m = monitor; + if (excludeTypes.includes(m.type) || m.type?.match(/sql$/)) { + return false; + } + const tld = parseTld(urlTypes.includes(m.type) ? m.url : m.type === "grpc-keyword" ? m.grpcUrl : m.hostname); + const rdap = await getRdapServer(tld.publicSuffix); + if (!rdap) { + log.warn("domain", `${tld.publicSuffix} is not supported. File a bug report if you believe it should be.`); + return false; + } + const existing = await DomainExpiry.findByName(tld.domain); + if (existing) { + return existing; + } + if (tld.domain) { + return await DomainExpiry.createByName(tld.domain); + } + } + + /** + * @returns {number} number of days remaining before expiry + */ + get daysRemaining() { + return getDaysRemaining(new Date(), new Date(this.expiry)); + } + + /** + * @returns {(Date|null)} Expiry date from RDAP + */ + getExpiryDate() { + return getRdapDomainExpiryDate(this.domain); + } + + /** + * @param {(Monitor)} monitor Monitor object + * @returns {Promise} + */ + static async checkExpiry(monitor) { + + let bean = await DomainExpiry.forMonitor(monitor); + + let expiryDate; + if (bean?.lastCheck && getDaysBetween(new Date(bean.lastCheck), new Date()) < 1) { + log.debug("domain", `Domain expiry already checked recently for ${bean.domain}, won't re-check.`); + return bean.expiry; + } else if (bean) { + expiryDate = await bean.getExpiryDate(); + + if (new Date(expiryDate) > new Date(bean.expiry)) { + bean.lastExpiryNotificationSent = null; + } + + bean.expiry = expiryDate; + bean.lastCheck = new Date(); + await R.store(bean); + } + + if (expiryDate === null) { + return; + } + + return expiryDate; + } + + /** + * @param {Monitor} monitor Monitor instance + * @param {LooseObject[]} notificationList notification List + * @returns {Promise} + */ + static async sendNotifications(monitor, notificationList) { + const domain = await DomainExpiry.forMonitor(monitor); + const name = domain.domain; + + if (!notificationList.length > 0) { + // fail fast. If no notification is set, all the following checks can be skipped. + log.debug("domain", "No notification, no need to send domain notification"); + return; + } + + const daysRemaining = getDaysRemaining(new Date(), domain.expiry); + const lastSent = domain.lastExpiryNotificationSent; + log.debug("domain", `${name} expires in ${daysRemaining} days`); + + let notifyDays = await setting("domainExpiryNotifyDays"); + if (notifyDays == null || !Array.isArray(notifyDays)) { + // Reset Default + await setSetting("domainExpiryNotifyDays", [ 7, 14, 21 ], "general"); + notifyDays = [ 7, 14, 21 ]; + } + if (Array.isArray(notifyDays)) { + // Asc sort to avoid sending multiple notifications if daysRemaining is below multiple targetDays + notifyDays.sort((a, b) => a - b); + for (const targetDays of notifyDays) { + if (daysRemaining > targetDays) { + log.debug( + "domain", + `No need to send domain notification for ${name} (${daysRemaining} days valid) on ${targetDays} deadline.` + ); + continue; + } else if (lastSent && lastSent <= targetDays) { + log.debug( + "domain", + `Notification for ${name} on ${targetDays} deadline sent already, no need to send again.` + ); + continue; + } + const sent = await sendDomainNotificationByTargetDays( + name, + daysRemaining, + targetDays, + notificationList + ); + if (sent) { + domain.lastExpiryNotificationSent = targetDays; + await R.store(domain); + return targetDays; + } + } + } + } +} + +module.exports = DomainExpiry; diff --git a/server/model/maintenance.js b/server/model/maintenance.js index 9c429752d..c180feec9 100644 --- a/server/model/maintenance.js +++ b/server/model/maintenance.js @@ -1,5 +1,5 @@ const { BeanModel } = require("redbean-node/dist/bean-model"); -const { parseTimeObject, parseTimeFromTimeObject, log } = require("../../src/util"); +const { parseTimeObject, parseTimeFromTimeObject, log, SQL_DATETIME_FORMAT } = require("../../src/util"); const { R } = require("redbean-node"); const dayjs = require("dayjs"); const Cron = require("croner"); @@ -262,7 +262,7 @@ class Maintenance extends BeanModel { }, duration); // Set last start date to current time - this.last_start_date = current.toISOString(); + this.last_start_date = current.utc().format(SQL_DATETIME_FORMAT); await R.store(this); }; diff --git a/server/model/monitor.js b/server/model/monitor.js index aa5d6ba9b..1c9a112cf 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -8,8 +8,8 @@ const { log, UP, DOWN, PENDING, MAINTENANCE, flipStatus, MAX_INTERVAL_SECOND, MI PING_COUNT_MIN, PING_COUNT_MAX, PING_COUNT_DEFAULT, PING_PER_REQUEST_TIMEOUT_MIN, PING_PER_REQUEST_TIMEOUT_MAX, PING_PER_REQUEST_TIMEOUT_DEFAULT } = require("../../src/util"); -const { ping, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, postgresQuery, mysqlQuery, setSetting, httpNtlm, radius, grpcQuery, - kafkaProducerAsync, getOidcTokenClientCredentials, rootCertificatesFingerprints, axiosAbortSignal +const { ping, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, mysqlQuery, setSetting, httpNtlm, radius, + kafkaProducerAsync, getOidcTokenClientCredentials, rootCertificatesFingerprints, axiosAbortSignal, checkCertificateHostname } = require("../util-server"); const { R } = require("redbean-node"); const { BeanModel } = require("redbean-node/dist/bean-model"); @@ -28,6 +28,7 @@ const { CookieJar } = require("tough-cookie"); const { HttpsCookieAgent } = require("http-cookie-agent/http"); const https = require("https"); const http = require("http"); +const DomainExpiry = require("./domain_expiry"); const rootCertificates = rootCertificatesFingerprints(); @@ -117,6 +118,7 @@ class Monitor extends BeanModel { keyword: this.keyword, invertKeyword: this.isInvertKeyword(), expiryNotification: this.isEnabledExpiryNotification(), + domainExpiryNotification: Boolean(this.domainExpiryNotification), ignoreTls: this.getIgnoreTls(), upsideDown: this.isUpsideDown(), packetSize: this.packetSize, @@ -359,7 +361,11 @@ class Monitor extends BeanModel { let previousBeat = null; let retries = 0; - this.prometheus = new Prometheus(this, await this.getTags()); + try { + this.prometheus = new Prometheus(this, await this.getTags()); + } catch (e) { + log.error("prometheus", "Please submit an issue to our GitHub repo. Prometheus update error: ", e.message); + } const beat = async () => { @@ -561,6 +567,7 @@ class Monitor extends BeanModel { tlsSocket.once("secureConnect", async () => { tlsInfo = checkCertificate(tlsSocket); tlsInfo.valid = tlsSocket.authorized || false; + tlsInfo.hostnameMatchMonitorUrl = checkCertificateHostname(tlsInfo.certInfo.raw, this.getUrl()?.hostname); await this.handleTlsInfo(tlsInfo); }); @@ -583,6 +590,7 @@ class Monitor extends BeanModel { if (tlsSocket) { tlsInfo = checkCertificate(tlsSocket); tlsInfo.valid = tlsSocket.authorized || false; + tlsInfo.hostnameMatchMonitorUrl = checkCertificateHostname(tlsInfo.certInfo.raw, this.getUrl()?.hostname); await this.handleTlsInfo(tlsInfo); } @@ -762,12 +770,14 @@ class Monitor extends BeanModel { let res = await axios.request(options); if (res.data.State.Running) { - if (res.data.State.Health && res.data.State.Health.Status !== "healthy") { - bean.status = PENDING; - bean.msg = res.data.State.Health.Status; - } else { + if (res.data.State.Health.Status === "healthy") { bean.status = UP; bean.msg = res.data.State.Health ? res.data.State.Health.Status : res.data.State.Status; + } else if (res.data.State.Health.Status === "unhealthy") { + throw Error("Container State is unhealthy"); + } else { + bean.status = PENDING; + bean.msg = res.data.State.Health.Status; } } else { throw Error("Container State is " + res.data.State.Status); @@ -777,45 +787,6 @@ class Monitor extends BeanModel { await mssqlQuery(this.databaseConnectionString, this.databaseQuery || "SELECT 1"); - bean.msg = ""; - bean.status = UP; - bean.ping = dayjs().valueOf() - startTime; - } else if (this.type === "grpc-keyword") { - let startTime = dayjs().valueOf(); - const options = { - grpcUrl: this.grpcUrl, - grpcProtobufData: this.grpcProtobuf, - grpcServiceName: this.grpcServiceName, - grpcEnableTls: this.grpcEnableTls, - grpcMethod: this.grpcMethod, - grpcBody: this.grpcBody, - }; - const response = await grpcQuery(options); - bean.ping = dayjs().valueOf() - startTime; - log.debug("monitor:", `gRPC response: ${JSON.stringify(response)}`); - let responseData = response.data; - if (responseData.length > 50) { - responseData = responseData.toString().substring(0, 47) + "..."; - } - if (response.code !== 1) { - bean.status = DOWN; - bean.msg = `Error in send gRPC ${response.code} ${response.errorMessage}`; - } else { - let keywordFound = response.data.toString().includes(this.keyword); - if (keywordFound === !this.isInvertKeyword()) { - bean.status = UP; - bean.msg = `${responseData}, keyword [${this.keyword}] ${keywordFound ? "is" : "not"} found`; - } else { - log.debug("monitor:", `GRPC response [${response.data}] + ", but keyword [${this.keyword}] is ${keywordFound ? "present" : "not"} in [" + ${response.data} + "]"`); - bean.status = DOWN; - bean.msg = `, but keyword [${this.keyword}] is ${keywordFound ? "present" : "not"} in [" + ${responseData} + "]`; - } - } - } else if (this.type === "postgres") { - let startTime = dayjs().valueOf(); - - await postgresQuery(this.databaseConnectionString, this.databaseQuery || "SELECT 1"); - bean.msg = ""; bean.status = UP; bean.ping = dayjs().valueOf() - startTime; @@ -860,6 +831,11 @@ class Monitor extends BeanModel { let startTime = dayjs().valueOf(); const monitorType = UptimeKumaServer.monitorTypeList[this.type]; await monitorType.check(this, bean, UptimeKumaServer.getInstance()); + + if (!monitorType.allowCustomStatus && bean.status !== UP) { + throw new Error("The monitor implementation is incorrect, non-UP error must throw error inside check()"); + } + if (!bean.ping) { bean.ping = dayjs().valueOf() - startTime; } @@ -960,6 +936,19 @@ class Monitor extends BeanModel { } } + if (bean.status !== MAINTENANCE && Boolean(this.domainExpiryNotification)) { + try { + const domainExpiryDate = await DomainExpiry.checkExpiry(this); + if (domainExpiryDate) { + DomainExpiry.sendNotifications(this, await Monitor.getNotificationList(this) || []); + } else { + log.debug("monitor", `Failed getting expiration date for domain ${this.name}`); + } + } catch (error) { + log.warn("monitor", `Failed to get domain expiry for ${this.name} : ${error.message}`); + } + } + if (bean.status === UP) { log.debug("monitor", `Monitor #${this.id} '${this.name}': Successful Response: ${bean.ping} ms | Interval: ${beatInterval} seconds | Type: ${this.type}`); } else if (bean.status === PENDING) { @@ -1227,6 +1216,9 @@ class Monitor extends BeanModel { // Send Cert Info await Monitor.sendCertInfo(io, monitorID, userID); + + // Send domain info + await Monitor.sendDomainInfo(io, monitorID, userID); } else { log.debug("monitor", "No clients in the room, no need to send stats"); } @@ -1248,6 +1240,22 @@ class Monitor extends BeanModel { } } + /** + * Send domain name information to client + * @param {Server} io Socket server instance + * @param {number} monitorID ID of monitor to send + * @param {number} userID ID of user to send to + * @returns {void} + */ + static async sendDomainInfo(io, monitorID, userID) { + const monitor = await R.findOne("monitor", "id = ?", [ monitorID ]); + + const domain = await DomainExpiry.forMonitor(monitor); + if (domain?.expiry) { + io.to(userID).emit("domainInfo", monitorID, domain.daysRemaining, new Date(domain.expiry)); + } + } + /** * Has status of monitor changed since last beat? * @param {boolean} isFirstBeat Is this the first beat of this monitor? diff --git a/server/monitor-types/dns.js b/server/monitor-types/dns.js index 5a47e4591..1565ff1f2 100644 --- a/server/monitor-types/dns.js +++ b/server/monitor-types/dns.js @@ -1,5 +1,5 @@ const { MonitorType } = require("./monitor-type"); -const { UP, DOWN } = require("../../src/util"); +const { UP } = require("../../src/util"); const dayjs = require("dayjs"); const { dnsResolve } = require("../util-server"); const { R } = require("redbean-node"); @@ -50,8 +50,10 @@ class DnsMonitorType extends MonitorType { break; case "CAA": - dnsMessage = dnsRes[0].issue; - conditionsResult = handleConditions({ record: dnsRes[0].issue }); + // .filter(Boolean) was added because some CAA records do not contain an issue key, resulting in a blank list item. + // Hypothetical dnsRes [{ critical: 0, issuewild: 'letsencrypt.org' }, { critical: 0, issue: 'letsencrypt.org' }] + dnsMessage = `Records: ${dnsRes.map(record => record.issue).filter(Boolean).join(" | ")}`; + conditionsResult = dnsRes.some(record => handleConditions({ record: record.issue })); break; case "MX": @@ -79,8 +81,12 @@ class DnsMonitorType extends MonitorType { await R.exec("UPDATE `monitor` SET dns_last_result = ? WHERE id = ? ", [ dnsMessage, monitor.id ]); } + if (!conditionsResult) { + throw new Error(dnsMessage); + } + heartbeat.msg = dnsMessage; - heartbeat.status = conditionsResult ? UP : DOWN; + heartbeat.status = UP; } } diff --git a/server/monitor-types/group.js b/server/monitor-types/group.js index 8372b4f17..212244a39 100644 --- a/server/monitor-types/group.js +++ b/server/monitor-types/group.js @@ -4,6 +4,7 @@ const Monitor = require("../model/monitor"); class GroupMonitorType extends MonitorType { name = "group"; + allowCustomStatus = true; /** * @inheritdoc diff --git a/server/monitor-types/grpc.js b/server/monitor-types/grpc.js new file mode 100644 index 000000000..ebc03b8c8 --- /dev/null +++ b/server/monitor-types/grpc.js @@ -0,0 +1,89 @@ +const { MonitorType } = require("./monitor-type"); +const { UP, log } = require("../../src/util"); +const dayjs = require("dayjs"); +const grpc = require("@grpc/grpc-js"); +const protojs = require("protobufjs"); + +class GrpcKeywordMonitorType extends MonitorType { + name = "grpc-keyword"; + + /** + * @inheritdoc + */ + async check(monitor, heartbeat, _server) { + const startTime = dayjs().valueOf(); + const service = this.constructGrpcService(monitor.grpcUrl, monitor.grpcProtobuf, monitor.grpcServiceName, monitor.grpcEnableTls); + let response = await this.grpcQuery(service, monitor.grpcMethod, monitor.grpcBody); + heartbeat.ping = dayjs().valueOf() - startTime; + log.debug(this.name, "gRPC response:", response); + let keywordFound = response.toString().includes(monitor.keyword); + if (keywordFound !== !monitor.isInvertKeyword()) { + log.debug(this.name, `GRPC response [${response}] + ", but keyword [${monitor.keyword}] is ${keywordFound ? "present" : "not"} in [" + ${response} + "]"`); + + let truncatedResponse = (response.length > 50) ? response.toString().substring(0, 47) + "..." : response; + + throw new Error(`keyword [${monitor.keyword}] is ${keywordFound ? "present" : "not"} in [" + ${truncatedResponse} + "]`); + } + heartbeat.status = UP; + heartbeat.msg = `${response}, keyword [${monitor.keyword}] ${keywordFound ? "is" : "not"} found`; + } + + /** + * Create gRPC client + * @param {string} url grpc Url + * @param {string} protobufData grpc ProtobufData + * @param {string} serviceName grpc ServiceName + * @param {string} enableTls grpc EnableTls + * @returns {grpc.Service} grpc Service + */ + constructGrpcService(url, protobufData, serviceName, enableTls) { + const protocObject = protojs.parse(protobufData); + const protoServiceObject = protocObject.root.lookupService(serviceName); + const Client = grpc.makeGenericClientConstructor({}); + const credentials = enableTls ? grpc.credentials.createSsl() : grpc.credentials.createInsecure(); + const client = new Client(url, credentials); + return protoServiceObject.create((method, requestData, cb) => { + const fullServiceName = method.fullName; + const serviceFQDN = fullServiceName.split("."); + const serviceMethod = serviceFQDN.pop(); + const serviceMethodClientImpl = `/${serviceFQDN.slice(1).join(".")}/${serviceMethod}`; + log.debug(this.name, `gRPC method ${serviceMethodClientImpl}`); + client.makeUnaryRequest( + serviceMethodClientImpl, + arg => arg, + arg => arg, + requestData, + cb); + }, false, false); + } + + /** + * Create gRPC client stib + * @param {grpc.Service} service grpc Url + * @param {string} method grpc Method + * @param {string} body grpc Body + * @returns {Promise} Result of gRPC query + */ + async grpcQuery(service, method, body) { + return new Promise((resolve, reject) => { + try { + service[method](JSON.parse(body), (err, response) => { + if (err) { + if (err.code !== 1) { + reject(err); + } + log.debug(this.name, `ignoring ${err.code} ${err.details}, as code=1 is considered OK`); + resolve(`${err.code} is considered OK because ${err.details}`); + } + resolve(JSON.stringify(response)); + }); + } catch (err) { + reject(err); + } + }); + } +} + +module.exports = { + GrpcKeywordMonitorType, +}; diff --git a/server/monitor-types/manual.js b/server/monitor-types/manual.js index e587b7409..7134d6c0f 100644 --- a/server/monitor-types/manual.js +++ b/server/monitor-types/manual.js @@ -8,6 +8,8 @@ class ManualMonitorType extends MonitorType { supportsConditions = false; conditionVariables = []; + allowCustomStatus = true; + /** * @inheritdoc */ diff --git a/server/monitor-types/monitor-type.js b/server/monitor-types/monitor-type.js index 8f3cbcac4..aa7b1d200 100644 --- a/server/monitor-types/monitor-type.js +++ b/server/monitor-types/monitor-type.js @@ -14,8 +14,17 @@ class MonitorType { */ conditionVariables = []; + /** + * Allows setting any custom status to heartbeat, other than UP. + * @type {boolean} + */ + allowCustomStatus = false; + /** * Run the monitoring check on the given monitor + * + * Successful cases: Should update heartbeat.status to "up" and set response time. + * Failure cases: Throw an error with a descriptive message. * @param {Monitor} monitor Monitor to check * @param {Heartbeat} heartbeat Monitor heartbeat to update * @param {UptimeKumaServer} server Uptime Kuma server diff --git a/server/monitor-types/postgres.js b/server/monitor-types/postgres.js new file mode 100644 index 000000000..6d6940191 --- /dev/null +++ b/server/monitor-types/postgres.js @@ -0,0 +1,83 @@ +const { MonitorType } = require("./monitor-type"); +const { log, UP } = require("../../src/util"); +const dayjs = require("dayjs"); +const postgresConParse = require("pg-connection-string").parse; +const { Client } = require("pg"); + +class PostgresMonitorType extends MonitorType { + name = "postgres"; + + /** + * @inheritdoc + */ + async check(monitor, heartbeat, _server) { + let startTime = dayjs().valueOf(); + + let query = monitor.databaseQuery; + // No query provided by user, use SELECT 1 + if (!query || (typeof query === "string" && query.trim() === "")) { + query = "SELECT 1"; + } + await this.postgresQuery(monitor.databaseConnectionString, query); + + heartbeat.msg = ""; + heartbeat.status = UP; + heartbeat.ping = dayjs().valueOf() - startTime; + } + + /** + * Run a query on Postgres + * @param {string} connectionString The database connection string + * @param {string} query The query to validate the database with + * @returns {Promise<(string[] | object[] | object)>} Response from + * server + */ + async postgresQuery(connectionString, query) { + return new Promise((resolve, reject) => { + const config = postgresConParse(connectionString); + + // Fix #3868, which true/false is not parsed to boolean + if (typeof config.ssl === "string") { + config.ssl = config.ssl === "true"; + } + + if (config.password === "") { + // See https://github.com/brianc/node-postgres/issues/1927 + reject(new Error("Password is undefined.")); + return; + } + const client = new Client(config); + + client.on("error", (error) => { + log.debug("postgres", "Error caught in the error event handler."); + reject(error); + }); + + client.connect((err) => { + if (err) { + reject(err); + client.end(); + } else { + // Connected here + try { + client.query(query, (err, res) => { + if (err) { + reject(err); + } else { + resolve(res); + } + client.end(); + }); + } catch (e) { + reject(e); + client.end(); + } + } + }); + }); + } +} + +module.exports = { + PostgresMonitorType, +}; diff --git a/server/monitor-types/rabbitmq.js b/server/monitor-types/rabbitmq.js index 165a0ed91..251f1b8ac 100644 --- a/server/monitor-types/rabbitmq.js +++ b/server/monitor-types/rabbitmq.js @@ -1,5 +1,5 @@ const { MonitorType } = require("./monitor-type"); -const { log, UP, DOWN } = require("../../src/util"); +const { log, UP } = require("../../src/util"); const { axiosAbortSignal } = require("../util-server"); const axios = require("axios"); @@ -17,7 +17,6 @@ class RabbitMqMonitorType extends MonitorType { throw new Error("Invalid RabbitMQ Nodes"); } - heartbeat.status = DOWN; for (let baseUrl of baseUrls) { try { // Without a trailing slash, path in baseUrl will be removed. https://example.com/api -> https://example.com @@ -45,17 +44,17 @@ class RabbitMqMonitorType extends MonitorType { heartbeat.msg = "OK"; break; } else if (res.status === 503) { - heartbeat.msg = res.data.reason; + throw new Error(res.data.reason); } else { - heartbeat.msg = `${res.status} - ${res.statusText}`; + throw new Error(`${res.status} - ${res.statusText}`); } } catch (error) { if (axios.isCancel(error)) { - heartbeat.msg = "Request timed out"; log.debug("monitor", `[${monitor.name}] Request timed out`); + throw new Error("Request timed out"); } else { log.debug("monitor", `[${monitor.name}] Axios Error: ${JSON.stringify(error.message)}`); - heartbeat.msg = error.message; + throw new Error(error.message); } } } diff --git a/server/monitor-types/tcp.js b/server/monitor-types/tcp.js index f0bc12a01..5223d2e25 100644 --- a/server/monitor-types/tcp.js +++ b/server/monitor-types/tcp.js @@ -1,5 +1,5 @@ const { MonitorType } = require("./monitor-type"); -const { UP, DOWN, PING_GLOBAL_TIMEOUT_DEFAULT: TIMEOUT, log } = require("../../src/util"); +const { UP, PING_GLOBAL_TIMEOUT_DEFAULT: TIMEOUT, log } = require("../../src/util"); const { checkCertificate } = require("../util-server"); const tls = require("tls"); const net = require("net"); @@ -47,21 +47,39 @@ class TCPMonitorType extends MonitorType { heartbeat.msg = `${resp} ms`; heartbeat.status = UP; } catch { - heartbeat.status = DOWN; - heartbeat.msg = "Connection failed"; - return; + throw new Error("Connection failed"); } let socket_; const preTLS = () => new Promise((resolve, reject) => { - let timeout; + let dialogTimeout; + let bannerTimeout; socket_ = net.connect(monitor.port, monitor.hostname); const onTimeout = () => { log.debug(this.name, `[${monitor.name}] Pre-TLS connection timed out`); - reject("Connection timed out"); + doReject("Connection timed out"); + }; + + const onBannerTimeout = () => { + log.debug(this.name, `[${monitor.name}] Pre-TLS timed out waiting for banner`); + // No banner. Could be a XMPP server? + socket_.write(``); + }; + + const doResolve = () => { + dialogTimeout && clearTimeout(dialogTimeout); + bannerTimeout && clearTimeout(bannerTimeout); + resolve({ socket: socket_ }); + }; + + const doReject = (error) => { + dialogTimeout && clearTimeout(dialogTimeout); + bannerTimeout && clearTimeout(bannerTimeout); + socket_.end(); + reject(error); }; socket_.on("connect", () => { @@ -72,10 +90,10 @@ class TCPMonitorType extends MonitorType { const response = data.toString(); const response_ = response.toLowerCase(); log.debug(this.name, `[${monitor.name}] Pre-TLS response: ${response}`); + clearTimeout(bannerTimeout); switch (true) { case response_.includes("start tls") || response_.includes("begin tls"): - timeout && clearTimeout(timeout); - resolve({ socket: socket_ }); + doResolve(); break; case response.startsWith("* OK") || response.match(/CAPABILITY.+STARTTLS/): socket_.write("a001 STARTTLS\r\n"); @@ -86,8 +104,16 @@ class TCPMonitorType extends MonitorType { case response.includes("250-STARTTLS"): socket_.write("STARTTLS\r\n"); break; + case response_.includes(""); + break; + case response_.includes(""): + break; default: - reject(`Unexpected response: ${response}`); + doReject(`Unexpected response: ${response}`); } }); socket_.on("error", error => { @@ -95,7 +121,8 @@ class TCPMonitorType extends MonitorType { reject(error); }); socket_.setTimeout(1000 * TIMEOUT, onTimeout); - timeout = setTimeout(onTimeout, 1000 * TIMEOUT); + dialogTimeout = setTimeout(onTimeout, 1000 * TIMEOUT); + bannerTimeout = setTimeout(onBannerTimeout, 1000 * 1.5); }); const reuseSocket = monitor.smtpSecurity === "starttls" ? await preTLS() : {}; @@ -133,13 +160,11 @@ class TCPMonitorType extends MonitorType { await monitor.handleTlsInfo(tlsInfoObject); if (!tlsInfoObject.valid) { - heartbeat.status = DOWN; - heartbeat.msg = "Certificate is invalid"; + throw new Error("Certificate is invalid"); } } catch (error) { const message = error instanceof Error ? error.message : "Unknown error"; - heartbeat.status = DOWN; - heartbeat.msg = `TLS Connection failed: ${message}`; + throw new Error(`TLS Connection failed: ${message}`); } finally { if (socket && !socket.destroyed) { socket.end(); diff --git a/server/monitor-types/websocket-upgrade.js b/server/monitor-types/websocket-upgrade.js index e85c4baa7..c53225306 100644 --- a/server/monitor-types/websocket-upgrade.js +++ b/server/monitor-types/websocket-upgrade.js @@ -1,6 +1,6 @@ const { MonitorType } = require("./monitor-type"); const WebSocket = require("ws"); -const { UP, DOWN } = require("../../src/util"); +const { UP } = require("../../src/util"); class WebSocketMonitorType extends MonitorType { name = "websocket-upgrade"; @@ -10,8 +10,13 @@ class WebSocketMonitorType extends MonitorType { */ async check(monitor, heartbeat, _server) { const [ message, code ] = await this.attemptUpgrade(monitor); - heartbeat.status = code === 1000 ? UP : DOWN; - heartbeat.msg = message; + + if (code === 1000) { + heartbeat.status = UP; + heartbeat.msg = message; + } else { + throw new Error(message); + } } /** diff --git a/server/routers/api-router.js b/server/routers/api-router.js index b00dbc02d..9c9a7e7e9 100644 --- a/server/routers/api-router.js +++ b/server/routers/api-router.js @@ -119,7 +119,12 @@ router.all("/api/push/:pushToken", async (request, response) => { io.to(monitor.user_id).emit("heartbeat", bean.toJSON()); Monitor.sendStats(io, monitor.id, monitor.user_id); - new Prometheus(monitor).update(bean, undefined); + + try { + new Prometheus(monitor, []).update(bean, undefined); + } catch (e) { + log.error("prometheus", "Please submit an issue to our GitHub repo. Prometheus update error: ", e.message); + } response.json({ ok: true, diff --git a/server/server.js b/server/server.js index d8088bc90..c8f2373fa 100644 --- a/server/server.js +++ b/server/server.js @@ -843,6 +843,7 @@ let needSetup = false; bean.invertKeyword = monitor.invertKeyword; bean.ignoreTls = monitor.ignoreTls; bean.expiryNotification = monitor.expiryNotification; + bean.domainExpiryNotification = monitor.domainExpiryNotification; bean.upsideDown = monitor.upsideDown; bean.packetSize = monitor.packetSize; bean.maxredirects = monitor.maxredirects; @@ -981,6 +982,22 @@ let needSetup = false; } }); + socket.on("checkMointor", async (partial, callback) => { + try { + checkLogin(socket); + const DomainExpiry = require("./model/domain_expiry"); + callback({ + ok: true, + domain: (await DomainExpiry.forMonitor(partial))?.domain || null + }); + } catch (e) { + callback({ + ok: false, + msg: e.message, + }); + } + }); + socket.on("getMonitorBeats", async (monitorID, period, callback) => { try { checkLogin(socket); @@ -1248,6 +1265,8 @@ let needSetup = false; value, ]); + await server.sendUpdateMonitorIntoList(socket, monitorID); + callback({ ok: true, msg: "successAdded", @@ -1272,6 +1291,8 @@ let needSetup = false; monitorID, ]); + await server.sendUpdateMonitorIntoList(socket, monitorID); + callback({ ok: true, msg: "successEdited", @@ -1296,6 +1317,8 @@ let needSetup = false; value, ]); + await server.sendUpdateMonitorIntoList(socket, monitorID); + callback({ ok: true, msg: "successDeleted", diff --git a/server/uptime-kuma-server.js b/server/uptime-kuma-server.js index 107b54671..b528cc3b3 100644 --- a/server/uptime-kuma-server.js +++ b/server/uptime-kuma-server.js @@ -113,10 +113,12 @@ class UptimeKumaServer { UptimeKumaServer.monitorTypeList["tailscale-ping"] = new TailscalePing(); UptimeKumaServer.monitorTypeList["websocket-upgrade"] = new WebSocketMonitorType(); UptimeKumaServer.monitorTypeList["dns"] = new DnsMonitorType(); + UptimeKumaServer.monitorTypeList["postgres"] = new PostgresMonitorType(); UptimeKumaServer.monitorTypeList["mqtt"] = new MqttMonitorType(); UptimeKumaServer.monitorTypeList["smtp"] = new SMTPMonitorType(); UptimeKumaServer.monitorTypeList["group"] = new GroupMonitorType(); UptimeKumaServer.monitorTypeList["snmp"] = new SNMPMonitorType(); + UptimeKumaServer.monitorTypeList["grpc-keyword"] = new GrpcKeywordMonitorType(); UptimeKumaServer.monitorTypeList["mongodb"] = new MongodbMonitorType(); UptimeKumaServer.monitorTypeList["rabbitmq"] = new RabbitMqMonitorType(); UptimeKumaServer.monitorTypeList["port"] = new TCPMonitorType(); @@ -220,7 +222,9 @@ class UptimeKumaServer { */ async sendUpdateMonitorIntoList(socket, monitorID) { let list = await this.getMonitorJSONList(socket.userID, monitorID); - this.io.to(socket.userID).emit("updateMonitorIntoList", list); + if (list && list[monitorID]) { + this.io.to(socket.userID).emit("updateMonitorIntoList", list); + } } /** @@ -557,10 +561,12 @@ const { RealBrowserMonitorType } = require("./monitor-types/real-browser-monitor const { TailscalePing } = require("./monitor-types/tailscale-ping"); const { WebSocketMonitorType } = require("./monitor-types/websocket-upgrade"); const { DnsMonitorType } = require("./monitor-types/dns"); +const { PostgresMonitorType } = require("./monitor-types/postgres"); const { MqttMonitorType } = require("./monitor-types/mqtt"); const { SMTPMonitorType } = require("./monitor-types/smtp"); const { GroupMonitorType } = require("./monitor-types/group"); const { SNMPMonitorType } = require("./monitor-types/snmp"); +const { GrpcKeywordMonitorType } = require("./monitor-types/grpc"); const { MongodbMonitorType } = require("./monitor-types/mongodb"); const { RabbitMqMonitorType } = require("./monitor-types/rabbitmq"); const { TCPMonitorType } = require("./monitor-types/tcp.js"); diff --git a/server/util-server.js b/server/util-server.js index 6365b623c..9ab324402 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -11,13 +11,9 @@ const iconv = require("iconv-lite"); const chardet = require("chardet"); const chroma = require("chroma-js"); const mssql = require("mssql"); -const { Client } = require("pg"); -const postgresConParse = require("pg-connection-string").parse; const mysql = require("mysql2"); const { NtlmClient } = require("./modules/axios-ntlm/lib/ntlmClient.js"); const { Settings } = require("./settings"); -const grpc = require("@grpc/grpc-js"); -const protojs = require("protobufjs"); const RadiusClient = require("./radius-client"); const oidc = require("openid-client"); const tls = require("tls"); @@ -351,64 +347,6 @@ exports.mssqlQuery = async function (connectionString, query) { } }; -/** - * Run a query on Postgres - * @param {string} connectionString The database connection string - * @param {string} query The query to validate the database with - * @returns {Promise<(string[] | object[] | object)>} Response from - * server - */ -exports.postgresQuery = function (connectionString, query) { - return new Promise((resolve, reject) => { - const config = postgresConParse(connectionString); - - // Fix #3868, which true/false is not parsed to boolean - if (typeof config.ssl === "string") { - config.ssl = config.ssl === "true"; - } - - if (config.password === "") { - // See https://github.com/brianc/node-postgres/issues/1927 - reject(new Error("Password is undefined.")); - return; - } - const client = new Client(config); - - client.on("error", (error) => { - log.debug("postgres", "Error caught in the error event handler."); - reject(error); - }); - - client.connect((err) => { - if (err) { - reject(err); - client.end(); - } else { - // Connected here - try { - // No query provided by user, use SELECT 1 - if (!query || (typeof query === "string" && query.trim() === "")) { - query = "SELECT 1"; - } - - client.query(query, (err, res) => { - if (err) { - reject(err); - } else { - resolve(res); - } - client.end(); - }); - } catch (e) { - reject(e); - client.end(); - } - } - }); - - }); -}; - /** * Run a query on MySQL/MariaDB * @param {string} connectionString The database connection string @@ -545,6 +483,7 @@ exports.setSettings = async function (type, data) { */ const getDaysBetween = (validFrom, validTo) => Math.round(Math.abs(+validFrom - +validTo) / 8.64e7); +exports.getDaysBetween = getDaysBetween; /** * Get days remaining from a time range @@ -554,11 +493,12 @@ const getDaysBetween = (validFrom, validTo) => */ const getDaysRemaining = (validFrom, validTo) => { const daysRemaining = getDaysBetween(validFrom, validTo); - if (new Date(validTo).getTime() < new Date().getTime()) { + if (new Date(validTo).getTime() < new Date(validFrom).getTime()) { return -daysRemaining; } return daysRemaining; }; +exports.getDaysRemaining = getDaysRemaining; /** * Fix certificate info for display @@ -638,6 +578,30 @@ exports.checkCertificate = function (socket) { }; }; +/** + * Checks if the certificate is valid for the provided hostname. + * Defaults to true if feature `X509Certificate` is not available, or input is not valid. + * @param {Buffer} certBuffer - The certificate buffer. + * @param {string} hostname - The hostname to compare against. + * @returns {boolean} True if the certificate is valid for the provided hostname, false otherwise. + */ +exports.checkCertificateHostname = function (certBuffer, hostname) { + let X509Certificate; + try { + X509Certificate = require("node:crypto").X509Certificate; + } catch (_) { + // X509Certificate is not available in this version of Node.js + return true; + } + + if (!X509Certificate || !certBuffer || !hostname) { + return true; + } + + let certObject = new X509Certificate(certBuffer); + return certObject.checkHost(hostname) !== undefined; +}; + /** * Check if the provided status code is within the accepted ranges * @param {number} status The status code to check @@ -892,64 +856,6 @@ module.exports.timeObjectToLocal = (obj, timezone = undefined) => { return timeObjectConvertTimezone(obj, timezone, false); }; -/** - * Create gRPC client stib - * @param {object} options from gRPC client - * @returns {Promise} Result of gRPC query - */ -module.exports.grpcQuery = async (options) => { - const { grpcUrl, grpcProtobufData, grpcServiceName, grpcEnableTls, grpcMethod, grpcBody } = options; - const protocObject = protojs.parse(grpcProtobufData); - const protoServiceObject = protocObject.root.lookupService(grpcServiceName); - const Client = grpc.makeGenericClientConstructor({}); - const credentials = grpcEnableTls ? grpc.credentials.createSsl() : grpc.credentials.createInsecure(); - const client = new Client( - grpcUrl, - credentials - ); - const grpcService = protoServiceObject.create(function (method, requestData, cb) { - const fullServiceName = method.fullName; - const serviceFQDN = fullServiceName.split("."); - const serviceMethod = serviceFQDN.pop(); - const serviceMethodClientImpl = `/${serviceFQDN.slice(1).join(".")}/${serviceMethod}`; - log.debug("monitor", `gRPC method ${serviceMethodClientImpl}`); - client.makeUnaryRequest( - serviceMethodClientImpl, - arg => arg, - arg => arg, - requestData, - cb); - }, false, false); - return new Promise((resolve, _) => { - try { - return grpcService[`${grpcMethod}`](JSON.parse(grpcBody), function (err, response) { - const responseData = JSON.stringify(response); - if (err) { - return resolve({ - code: err.code, - errorMessage: err.details, - data: "" - }); - } else { - log.debug("monitor:", `gRPC response: ${JSON.stringify(response)}`); - return resolve({ - code: 1, - errorMessage: "", - data: responseData - }); - } - }); - } catch (err) { - return resolve({ - code: -1, - errorMessage: `Error ${err}. Please review your gRPC configuration option. The service name must not include package name value, and the method name must follow camelCase format`, - data: "" - }); - } - - }); -}; - /** * Returns an array of SHA256 fingerprints for all known root certificates. * @returns {Set} A set of SHA256 fingerprints. diff --git a/src/components/HeartbeatBar.vue b/src/components/HeartbeatBar.vue index de5c86dcc..55defd4e3 100644 --- a/src/components/HeartbeatBar.vue +++ b/src/components/HeartbeatBar.vue @@ -85,7 +85,6 @@ export default { tooltipTimeoutId: null, // Canvas hoveredBeatIndex: -1, - beatBorderRadius: 2.5, }; }, computed: { @@ -316,6 +315,13 @@ export default { }); }, + "$root.theme"() { + // Redraw canvas when theme changes (nextTick ensures .dark class is applied) + this.$nextTick(() => { + this.drawCanvas(); + }); + }, + hoveredBeatIndex() { this.drawCanvas(); }, @@ -551,13 +557,14 @@ export default { const centerY = this.canvasHeight / 2; // Cache CSS colors once per redraw - const styles = getComputedStyle(document.documentElement); + const rootStyles = getComputedStyle(document.documentElement); + const canvasStyles = getComputedStyle(canvas.parentElement); const colors = { - empty: styles.getPropertyValue("--bs-body-bg") || "#f0f8ff", - down: styles.getPropertyValue("--bs-danger") || "#dc3545", - pending: styles.getPropertyValue("--bs-warning") || "#ffc107", - maintenance: styles.getPropertyValue("--maintenance") || "#1d4ed8", - up: styles.getPropertyValue("--bs-primary") || "#5cdd8b", + empty: canvasStyles.getPropertyValue("--beat-empty-color") || "#f0f8ff", + down: rootStyles.getPropertyValue("--bs-danger") || "#dc3545", + pending: rootStyles.getPropertyValue("--bs-warning") || "#ffc107", + maintenance: rootStyles.getPropertyValue("--maintenance") || "#1d4ed8", + up: rootStyles.getPropertyValue("--bs-primary") || "#5cdd8b", }; // Draw each beat @@ -578,19 +585,22 @@ export default { offsetY = centerY - height / 2; } + // Calculate border radius based on current width (pill shape = half of width) + const borderRadius = width / 2; + // Get color based on beat status let color = this.getBeatColor(beat, colors); // Draw beat rectangle ctx.fillStyle = color; - this.roundRect(ctx, offsetX, offsetY, width, height, this.beatBorderRadius); + this.roundRect(ctx, offsetX, offsetY, width, height, borderRadius); ctx.fill(); // Apply hover opacity if (isHovered && beat !== 0) { ctx.globalAlpha = 0.8; ctx.fillStyle = color; - this.roundRect(ctx, offsetX, offsetY, width, height, this.beatBorderRadius); + this.roundRect(ctx, offsetX, offsetY, width, height, borderRadius); ctx.fill(); ctx.globalAlpha = 1; } @@ -813,6 +823,12 @@ export default { } .hp-bar-big { + --beat-empty-color: #f0f8ff; + + .dark & { + --beat-empty-color: #848484; + } + .heartbeat-canvas { display: block; cursor: pointer; diff --git a/src/components/notifications/Pushover.vue b/src/components/notifications/Pushover.vue index e2fecd29f..606a9b152 100644 --- a/src/components/notifications/Pushover.vue +++ b/src/components/notifications/Pushover.vue @@ -17,14 +17,14 @@ - + - + + +
{{ monitor.humanReadableInterval }}
+ +
+ {{ $t("minimumIntervalWarning") }} +
@@ -736,7 +752,19 @@ {{ $t("Heartbeat Retry Interval") }} ({{ $t("retryCheckEverySecond", [ monitor.retryInterval ]) }}) - + +
+ {{ $t("minimumIntervalWarning") }} +
@@ -769,6 +797,14 @@ +
+ + +
+
+
@@ -1251,6 +1287,10 @@ + +

{{ $t("lowIntervalWarning") }}

+

{{ $t("Please use this option carefully!") }}

+
@@ -1261,6 +1301,7 @@ import { useToast } from "vue-toastification"; import ActionSelect from "../components/ActionSelect.vue"; import CopyableInput from "../components/CopyableInput.vue"; import CreateGroupDialog from "../components/CreateGroupDialog.vue"; +import Confirm from "../components/Confirm.vue"; import NotificationDialog from "../components/NotificationDialog.vue"; import DockerHostDialog from "../components/DockerHostDialog.vue"; import RemoteBrowserDialog from "../components/RemoteBrowserDialog.vue"; @@ -1298,6 +1339,7 @@ const monitorDefaults = { ignoreTls: false, upsideDown: false, expiryNotification: false, + domainExpiryNotification: true, maxredirects: 10, accepted_statuscodes: [ "200-299" ], dns_resolve_type: "A", @@ -1336,6 +1378,7 @@ export default { ProxyDialog, CopyableInput, CreateGroupDialog, + Confirm, NotificationDialog, DockerHostDialog, RemoteBrowserDialog, @@ -1353,6 +1396,7 @@ export default { notificationIDList: {}, // Do not add default value here, please check init() method }, + hasDomain: false, acceptedStatusCodeOptions: [], dnsresolvetypeOptions: [], kafkaSaslMechanismOptions: [], @@ -1368,6 +1412,10 @@ export default { }, draftGroupName: null, remoteBrowsersEnabled: false, + lowIntervalConfirmation: { + confirmed: false, + editedValue: false, + }, }; }, @@ -1423,6 +1471,16 @@ export default { return null; }, + monitorTypeUrlHost() { + const { type, url, hostname, grpcUrl } = this.monitor; + return { + type, + url, + hostname, + grpcUrl + }; + }, + pageName() { let name = "Add New Monitor"; if (this.isClone) { @@ -1700,6 +1758,15 @@ message HealthCheckResponse { } }, + "monitorTypeUrlHost"(data) { + this.$root.getSocket().emit("checkMointor", data, (res) => { + this.hasDomain = !!res?.domain; + if (!res?.domain) { + this.monitor.domainExpiryNotification = false; + } + }); + }, + "monitor.type"(newType, oldType) { if (oldType && this.monitor.type === "websocket-upgrade") { this.monitor.url = "wss://"; @@ -1995,6 +2062,11 @@ message HealthCheckResponse { this.monitor.pushToken = genSecret(pushTokenLength); }, + handleIntervalConfirm() { + this.lowIntervalConfirmation.confirmed = true; + this.submit(); + }, + /** * Submit the form data for processing * @returns {Promise} @@ -2003,6 +2075,15 @@ message HealthCheckResponse { this.processing = true; + // Check user has confirmed use of low interval value. Only + // do this if the interval value has changed since last save. + if (this.lowIntervalConfirmation.editedValue && (this.monitor.interval < 20 || this.monitor.retryInterval < 20) && !this.lowIntervalConfirmation.confirmed) { + // The dialog will then re-call submit + this.$refs.confirmLowIntervalValue.show(); + this.processing = false; + return; + } + if (!this.monitor.name) { this.monitor.name = this.defaultFriendlyName; } @@ -2012,6 +2093,9 @@ message HealthCheckResponse { return; } + this.lowIntervalConfirmation.confirmed = false; + this.lowIntervalConfirmation.editedValue = false; + // Beautify the JSON format (only if httpBodyEncoding is not set or === json) if (this.monitor.body && (!this.monitor.httpBodyEncoding || this.monitor.httpBodyEncoding === "json")) { this.monitor.body = JSON.stringify(JSON.parse(this.monitor.body), null, 4); diff --git a/src/pages/List.vue b/src/pages/List.vue index dd2d46059..2d8db2dba 100644 --- a/src/pages/List.vue +++ b/src/pages/List.vue @@ -11,6 +11,18 @@ export default { components: { MonitorList, }, + watch: { + "$root.isMobile"(newVal) { + if (!newVal && this.$route.path === "/list") { + this.$router.replace({ path: "/dashboard" }); + } + }, + }, + mounted() { + if (!this.$root.isMobile && this.$route.path === "/list") { + this.$router.replace({ path: "/dashboard" }); + } + }, }; @@ -20,5 +32,4 @@ export default { .shadow-box { padding: 20px; } - diff --git a/src/pages/Settings.vue b/src/pages/Settings.vue index 96bb1fee1..eac9dd48d 100644 --- a/src/pages/Settings.vue +++ b/src/pages/Settings.vue @@ -179,6 +179,10 @@ export default { this.settings.tlsExpiryNotifyDays = [ 7, 14, 21 ]; } + if (this.settings.domainExpiryNotifyDays === undefined) { + this.settings.domainExpiryNotifyDays = [ 7, 14, 21 ]; + } + if (this.settings.trustProxy === undefined) { this.settings.trustProxy = false; } diff --git a/src/pages/StatusPage.vue b/src/pages/StatusPage.vue index bf35ab21a..74a5c3f66 100644 --- a/src/pages/StatusPage.vue +++ b/src/pages/StatusPage.vue @@ -161,14 +161,14 @@ -
+
- - + {{ $t("Go to Dashboard") }} diff --git a/src/util.js b/src/util.js index 9ceaaf064..a156ae762 100644 --- a/src/util.js +++ b/src/util.js @@ -30,7 +30,7 @@ exports.SQL_DATE_FORMAT = "YYYY-MM-DD"; exports.SQL_DATETIME_FORMAT = "YYYY-MM-DD HH:mm:ss"; exports.SQL_DATETIME_FORMAT_WITHOUT_SECOND = "YYYY-MM-DD HH:mm"; exports.MAX_INTERVAL_SECOND = 2073600; -exports.MIN_INTERVAL_SECOND = 20; +exports.MIN_INTERVAL_SECOND = 1; exports.PING_PACKET_SIZE_MIN = 1; exports.PING_PACKET_SIZE_MAX = 65500; exports.PING_PACKET_SIZE_DEFAULT = 56; @@ -227,11 +227,7 @@ class Logger { this.log(module, "debug", ...msg); } exception(module, exception, ...msg) { - let finalMessage = exception; - if (msg) { - finalMessage = `${msg}: ${exception}`; - } - this.log(module, "error", finalMessage); + this.log(module, "error", ...msg, exception); } } exports.log = new Logger(); @@ -400,6 +396,12 @@ async function evaluateJsonQuery(data, jsonPath, jsonPathOperator, expectedValue if (response === null || response === undefined) { throw new Error("Empty or undefined response. Check query syntax and response structure"); } + if (Array.isArray(response)) { + const responseStr = JSON.stringify(response); + const truncatedResponse = responseStr.length > 25 ? responseStr.substring(0, 25) + "...]" : responseStr; + throw new Error("JSON query returned the array " + truncatedResponse + ", but a primitive value is required. " + + "Modify your query to return a single value via [0] to get the first element or use an aggregation like $count(), $sum() or $boolean()."); + } if (typeof response === "object" || response instanceof Date || typeof response === "function") { throw new Error(`The post-JSON query evaluated response from the server is of type ${typeof response}, which cannot be directly compared to the expected value`); } diff --git a/src/util.ts b/src/util.ts index 6bf9501b5..2fe92bf7c 100644 --- a/src/util.ts +++ b/src/util.ts @@ -44,7 +44,7 @@ export const SQL_DATETIME_FORMAT = "YYYY-MM-DD HH:mm:ss"; export const SQL_DATETIME_FORMAT_WITHOUT_SECOND = "YYYY-MM-DD HH:mm"; export const MAX_INTERVAL_SECOND = 2073600; // 24 days -export const MIN_INTERVAL_SECOND = 20; // 20 seconds +export const MIN_INTERVAL_SECOND = 1; // 1 second // Packet Size limits export const PING_PACKET_SIZE_MIN = 1; @@ -674,6 +674,16 @@ export async function evaluateJsonQuery(data: any, jsonPath: string, jsonPathOpe throw new Error("Empty or undefined response. Check query syntax and response structure"); } + // Check for arrays: JSONata filter expressions like .[predicate] always return arrays + if (Array.isArray(response)) { + const responseStr = JSON.stringify(response); + const truncatedResponse = responseStr.length > 25 ? responseStr.substring(0, 25) + "...]" : responseStr; + throw new Error( + "JSON query returned the array " + truncatedResponse + ", but a primitive value is required. " + + "Modify your query to return a single value via [0] to get the first element or use an aggregation like $count(), $sum() or $boolean()." + ); + } + if (typeof response === "object" || response instanceof Date || typeof response === "function") { throw new Error(`The post-JSON query evaluated response from the server is of type ${typeof response}, which cannot be directly compared to the expected value`); } diff --git a/test/backend-test/test-cert-hostname-match.js b/test/backend-test/test-cert-hostname-match.js new file mode 100644 index 000000000..fb7c822ed --- /dev/null +++ b/test/backend-test/test-cert-hostname-match.js @@ -0,0 +1,47 @@ +const { test } = require("node:test"); + +const assert = require("node:assert"); + +const { checkCertificateHostname } = require("../../server/util-server"); + +const testCert = ` +-----BEGIN CERTIFICATE----- +MIIFCTCCA/GgAwIBAgISBEROD0/r+BjpW4TvWCcZYxjpMA0GCSqGSIb3DQEBCwUA +MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD +EwJSMzAeFw0yMzA5MDQxMjExMThaFw0yMzEyMDMxMjExMTdaMBQxEjAQBgNVBAMM +CSouZWZmLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALywpmHr +GOFlhw9CcW11fVloL6dceeUexbIwVd/gOt0/rIlgBViOGCh1pFYA/Essty4vXBzx +cp6W4WurmwU6ZOJA0/T6rxnmsjxSdrHVGBGgW18HJ9IWqBl9MigjpRo9h4SlAPJq +cAsiBfPhQ0oSe/8IqwgKA4HTvlcTf5/HKnbe0MyQt7WNILWHm+zpfLE0AmLVXxqA +MNc/ynQDLTsWDZnqqri4MKOW1yOAMbUoAWSsNaagoGnZU4bg8uhu/2JTi/vdjl0g +fTDOjsELc70cWekZ9Mv4ND4w3SEthotbMCCtZE5bUqcGzSm4pQEJ37kQ7xjJ0onT +RRcuZI6/jDWzwZ0CAwEAAaOCAjUwggIxMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUE +FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU +hTqVTd8TZ2pknzGJtKw2JaIrPJAwHwYDVR0jBBgwFoAUFC6zF7dYVsuuUAlA5h+v +nYsUwsYwVQYIKwYBBQUHAQEESTBHMCEGCCsGAQUFBzABhhVodHRwOi8vcjMuby5s +ZW5jci5vcmcwIgYIKwYBBQUHMAKGFmh0dHA6Ly9yMy5pLmxlbmNyLm9yZy8wPwYD +VR0RBDgwNoIJKi5lZmYub3JnghEqLnN0YWdpbmcuZWZmLm9yZ4IWd3d3Lmh0dHBz +LXJ1bGVzZXRzLm9yZzATBgNVHSAEDDAKMAgGBmeBDAECATCCAQMGCisGAQQB1nkC +BAIEgfQEgfEA7wB2ALc++yTfnE26dfI5xbpY9Gxd/ELPep81xJ4dCYEl7bSZAAAB +imBRp0EAAAQDAEcwRQIhAMW3HZwWZWXPWfahH2pr/lxCcoSluHv2huAW6rlzU3zn +AiAOzD/p8F3gT1bzDgdSW+X5WDBeU+EutRbHMSV+Cx0mZwB1AHoyjFTYty22IOo4 +4FIe6YQWcDIThU070ivBOlejUutSAAABimBRqRQAAAQDAEYwRAIgFXvRRZS3xx83 +XdTsnto5SxSnGi1+YfzYobMdV1yqHGACIDurLvkt58TwifUbyXflGZJmOMhcC2G1 +KUd29yCUjIahMA0GCSqGSIb3DQEBCwUAA4IBAQA6t2F3PKMLlb2A/JsQhPFUJLS3 +6cx+97dzROQLBdnUQIMxPkJBN/lltNdsVxJa4A3DMbrJOayefX2l8UIvFiEFVseF +WrxbmXDF68fwhBKBgeqZ25/S8jEdP5PWYWXHgXvx0zRdhfe9vuba5WeFyz79cR7K +t3bSyv6GMJ2z3qBkVFGHSeYakcxPWes3CNmGxInwZNBXA2oc7xuncFrjno/USzUI +nEefDfF3H3jC+0iP3IpsK8orwgWz4lOkcMYdan733lSZuVJ6pm7C9phTV04NGF3H +iPenGDCg1awOyRnvxNq1MtMDkR9AHwksukzwiYNexYjyvE2t0UzXhFXwazQ3 +-----END CERTIFICATE----- +`; + +test("Certificate and hostname match", () => { + const result = checkCertificateHostname(testCert, "www.eff.org"); + assert.strictEqual(result, true); +}); + +test("Certificate and hostname mismatch", () => { + const result = checkCertificateHostname(testCert, "example.com"); + assert.strictEqual(result, false); +}); diff --git a/test/backend-test/test-domain.js b/test/backend-test/test-domain.js new file mode 100644 index 000000000..aa3102e37 --- /dev/null +++ b/test/backend-test/test-domain.js @@ -0,0 +1,70 @@ +process.env.UPTIME_KUMA_HIDE_LOG = [ "info_db", "info_server" ].join(","); + +const test = require("node:test"); +const assert = require("node:assert"); +const DomainExpiry = require("../../server/model/domain_expiry"); +const mockWebhook = require("../mock-webhook"); +const TestDB = require("../mock-testdb"); +const { R } = require("redbean-node"); +const { Notification } = require("../../server/notification"); +const { Settings } = require("../../server/settings"); +const { setSetting } = require("../../server/util-server"); + +const testDb = new TestDB(); + +test("Domain Expiry", async (t) => { + await testDb.create(); + Notification.init(); + + const monHttpCom = { + type: "http", + url: "https://www.google.com", + domainExpiryNotification: true + }; + await t.test("Should get expiry date for .wiki with no A record", async () => { + const d = DomainExpiry.createByName("google.wiki"); + assert.deepEqual(await d.getExpiryDate(), new Date("2026-11-26T23:59:59.000Z")); + }); + await t.test("Should get expiration date for .com from RDAP", async () => { + const domain = await DomainExpiry.forMonitor(monHttpCom); + const expiryFromRdap = await domain.getExpiryDate(); // from RDAP + assert.deepEqual(expiryFromRdap, new Date("2028-09-14T04:00:00.000Z")); + }); + await t.test("Should have expiration date cached in database", async () => { + await DomainExpiry.checkExpiry(monHttpCom); // RDAP -> Cache + const domain = await DomainExpiry.findByName("google.com"); + assert(Date.now() - domain.lastCheck < 5 * 1000); + }); + await t.test("Should trigger notify for expiring domain", async () => { + await DomainExpiry.findByName("google.com"); + const hook = { + "port": 3010, + "url": "capture" + }; + await setSetting("domainExpiryNotifyDays", [ 1, 2, 1500 ], "general"); + const notif = R.convertToBean("notification", { + "config": JSON.stringify({ + type: "webhook", + httpMethod: "post", + webhookContentType: "json", + webhookURL: `http://127.0.0.1:${hook.port}/${hook.url}` + }), + "active": 1, + "user_id": 1, + "name": "Testhook" + }); + const manyDays = 1500; + setSetting("domainExpiryNotifyDays", [ 7, 14, manyDays ], "general"); + const [ notifRet, data ] = await Promise.all([ + DomainExpiry.sendNotifications(monHttpCom, [ notif ]), + mockWebhook(hook.port, hook.url) + ]); + assert.equal(notifRet, manyDays); + assert.match(data.msg, /will expire in/); + }); +}).finally(() => { + setTimeout(async () => { + Settings.stopCacheCleaner(); + await testDb.destroy(); + }, 200); +}); diff --git a/test/backend-test/test-grpc.js b/test/backend-test/test-grpc.js new file mode 100644 index 000000000..31b588cff --- /dev/null +++ b/test/backend-test/test-grpc.js @@ -0,0 +1,306 @@ +const { describe, test } = require("node:test"); +const assert = require("node:assert"); +const grpc = require("@grpc/grpc-js"); +const protoLoader = require("@grpc/proto-loader"); +const { GrpcKeywordMonitorType } = require("../../server/monitor-types/grpc"); +const { UP, PENDING } = require("../../src/util"); +const fs = require("fs"); +const path = require("path"); +const os = require("os"); + +const testProto = ` +syntax = "proto3"; +package test; + +service TestService { + rpc Echo (EchoRequest) returns (EchoResponse); +} + +message EchoRequest { + string message = 1; +} + +message EchoResponse { + string message = 1; +} +`; + +/** + * Create a gRPC server for testing + * @param {number} port Port to listen on + * @param {object} methodHandlers Object with method handlers + * @returns {Promise} gRPC server instance + */ +async function createTestGrpcServer(port, methodHandlers) { + // Write proto to temp file + const tmpDir = os.tmpdir(); + const protoPath = path.join(tmpDir, `test-${port}.proto`); + fs.writeFileSync(protoPath, testProto); + + // Load proto file + const packageDefinition = protoLoader.loadSync(protoPath, { + keepCase: true, + longs: String, + enums: String, + defaults: true, + oneofs: true + }); + const protoDescriptor = grpc.loadPackageDefinition(packageDefinition); + const testPackage = protoDescriptor.test; + + const server = new grpc.Server(); + + // Add service implementation + server.addService(testPackage.TestService.service, { + Echo: (call, callback) => { + if (methodHandlers.Echo) { + methodHandlers.Echo(call, callback); + } else { + callback(null, { message: call.request.message }); + } + }, + }); + + return new Promise((resolve, reject) => { + server.bindAsync( + `0.0.0.0:${port}`, + grpc.ServerCredentials.createInsecure(), + (err) => { + if (err) { + reject(err); + } else { + server.start(); + // Clean up temp file + fs.unlinkSync(protoPath); + resolve(server); + } + } + ); + }); +} + +describe("GrpcKeywordMonitorType", { + skip: !!process.env.CI && (process.platform !== "linux" || process.arch !== "x64"), +}, () => { + test("gRPC keyword found in response", async () => { + const port = 50051; + const server = await createTestGrpcServer(port, { + Echo: (call, callback) => { + callback(null, { message: "Hello World with SUCCESS keyword" }); + } + }); + + const grpcMonitor = new GrpcKeywordMonitorType(); + const monitor = { + grpcUrl: `localhost:${port}`, + grpcProtobuf: testProto, + grpcServiceName: "test.TestService", + grpcMethod: "echo", + grpcBody: JSON.stringify({ message: "test" }), + keyword: "SUCCESS", + invertKeyword: false, + grpcEnableTls: false, + isInvertKeyword: () => false, + }; + + const heartbeat = { + msg: "", + status: PENDING, + }; + + try { + await grpcMonitor.check(monitor, heartbeat, {}); + assert.strictEqual(heartbeat.status, UP); + assert.ok(heartbeat.msg.includes("SUCCESS")); + assert.ok(heartbeat.msg.includes("is")); + } finally { + server.forceShutdown(); + } + }); + + test("gRPC keyword not found in response", async () => { + const port = 50052; + const server = await createTestGrpcServer(port, { + Echo: (call, callback) => { + callback(null, { message: "Hello World without the expected keyword" }); + } + }); + + const grpcMonitor = new GrpcKeywordMonitorType(); + const monitor = { + grpcUrl: `localhost:${port}`, + grpcProtobuf: testProto, + grpcServiceName: "test.TestService", + grpcMethod: "echo", + grpcBody: JSON.stringify({ message: "test" }), + keyword: "MISSING", + invertKeyword: false, + grpcEnableTls: false, + isInvertKeyword: () => false, + }; + + const heartbeat = { + msg: "", + status: PENDING, + }; + + try { + await assert.rejects( + grpcMonitor.check(monitor, heartbeat, {}), + (err) => { + assert.ok(err.message.includes("MISSING")); + assert.ok(err.message.includes("not")); + return true; + } + ); + } finally { + server.forceShutdown(); + } + }); + + test("gRPC inverted keyword - keyword present (should fail)", async () => { + const port = 50053; + const server = await createTestGrpcServer(port, { + Echo: (call, callback) => { + callback(null, { message: "Response with ERROR keyword" }); + } + }); + + const grpcMonitor = new GrpcKeywordMonitorType(); + const monitor = { + grpcUrl: `localhost:${port}`, + grpcProtobuf: testProto, + grpcServiceName: "test.TestService", + grpcMethod: "echo", + grpcBody: JSON.stringify({ message: "test" }), + keyword: "ERROR", + invertKeyword: true, + grpcEnableTls: false, + isInvertKeyword: () => true, + }; + + const heartbeat = { + msg: "", + status: PENDING, + }; + + try { + await assert.rejects( + grpcMonitor.check(monitor, heartbeat, {}), + (err) => { + assert.ok(err.message.includes("ERROR")); + assert.ok(err.message.includes("present")); + return true; + } + ); + } finally { + server.forceShutdown(); + } + }); + + test("gRPC inverted keyword - keyword not present (should pass)", async () => { + const port = 50054; + const server = await createTestGrpcServer(port, { + Echo: (call, callback) => { + callback(null, { message: "Response without error keyword" }); + } + }); + + const grpcMonitor = new GrpcKeywordMonitorType(); + const monitor = { + grpcUrl: `localhost:${port}`, + grpcProtobuf: testProto, + grpcServiceName: "test.TestService", + grpcMethod: "echo", + grpcBody: JSON.stringify({ message: "test" }), + keyword: "ERROR", + invertKeyword: true, + grpcEnableTls: false, + isInvertKeyword: () => true, + }; + + const heartbeat = { + msg: "", + status: PENDING, + }; + + try { + await grpcMonitor.check(monitor, heartbeat, {}); + assert.strictEqual(heartbeat.status, UP); + assert.ok(heartbeat.msg.includes("ERROR")); + assert.ok(heartbeat.msg.includes("not")); + } finally { + server.forceShutdown(); + } + }); + + test("gRPC connection failure", async () => { + const grpcMonitor = new GrpcKeywordMonitorType(); + const monitor = { + grpcUrl: "localhost:50099", + grpcProtobuf: testProto, + grpcServiceName: "test.TestService", + grpcMethod: "echo", + grpcBody: JSON.stringify({ message: "test" }), + keyword: "SUCCESS", + invertKeyword: false, + grpcEnableTls: false, + isInvertKeyword: () => false, + }; + + const heartbeat = { + msg: "", + status: PENDING, + }; + + await assert.rejects( + grpcMonitor.check(monitor, heartbeat, {}), + (err) => { + // Should fail with connection error + return true; + } + ); + }); + + test("gRPC response truncation for long messages", async () => { + const port = 50055; + const longMessage = "A".repeat(100) + " with SUCCESS keyword"; + + const server = await createTestGrpcServer(port, { + Echo: (call, callback) => { + callback(null, { message: longMessage }); + } + }); + + const grpcMonitor = new GrpcKeywordMonitorType(); + const monitor = { + grpcUrl: `localhost:${port}`, + grpcProtobuf: testProto, + grpcServiceName: "test.TestService", + grpcMethod: "echo", + grpcBody: JSON.stringify({ message: "test" }), + keyword: "MISSING", + invertKeyword: false, + grpcEnableTls: false, + isInvertKeyword: () => false, + }; + + const heartbeat = { + msg: "", + status: PENDING, + }; + + try { + await assert.rejects( + grpcMonitor.check(monitor, heartbeat, {}), + (err) => { + // Should truncate message to 50 characters with "..." + assert.ok(err.message.includes("...")); + return true; + } + ); + } finally { + server.forceShutdown(); + } + }); +}); diff --git a/test/backend-test/test-maintenance.js b/test/backend-test/test-maintenance.js new file mode 100644 index 000000000..a23bd77bb --- /dev/null +++ b/test/backend-test/test-maintenance.js @@ -0,0 +1,65 @@ +const test = require("node:test"); +const assert = require("node:assert"); +const dayjs = require("dayjs"); +const { SQL_DATETIME_FORMAT } = require("../../src/util"); + +dayjs.extend(require("dayjs/plugin/utc")); +dayjs.extend(require("dayjs/plugin/customParseFormat")); + +/** + * Tests for maintenance date formatting to ensure compatibility with MariaDB/MySQL. + * Issue: MariaDB rejects ISO format dates like '2025-12-19T01:04:02.129Z' + * Fix: Use SQL_DATETIME_FORMAT ('YYYY-MM-DD HH:mm:ss') instead of toISOString() + */ +test("Maintenance Date Format - MariaDB Compatibility", async (t) => { + + await t.test("SQL_DATETIME_FORMAT constant should match MariaDB format", async () => { + assert.strictEqual(SQL_DATETIME_FORMAT, "YYYY-MM-DD HH:mm:ss"); + }); + + await t.test("Format date using SQL_DATETIME_FORMAT", async () => { + const current = dayjs.utc("2025-12-19T01:04:02.129Z"); + const sqlFormat = current.utc().format(SQL_DATETIME_FORMAT); + + assert.strictEqual(sqlFormat, "2025-12-19 01:04:02"); + }); + + await t.test("SQL format should not contain ISO markers (T, Z)", async () => { + const current = dayjs.utc("2025-12-19T01:04:02.129Z"); + const sqlFormat = current.utc().format(SQL_DATETIME_FORMAT); + + assert.strictEqual(sqlFormat.includes("T"), false, "SQL format should not contain 'T'"); + assert.strictEqual(sqlFormat.includes("Z"), false, "SQL format should not contain 'Z'"); + }); + + await t.test("SQL format should match YYYY-MM-DD HH:mm:ss pattern", async () => { + const current = dayjs.utc("2025-12-19T01:04:02.129Z"); + const sqlFormat = current.utc().format(SQL_DATETIME_FORMAT); + const sqlDateTimeRegex = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/; + + assert.strictEqual(sqlDateTimeRegex.test(sqlFormat), true); + }); + + await t.test("Parse SQL datetime back to dayjs preserves timestamp", async () => { + const originalDate = dayjs.utc("2025-12-19T01:04:02.000Z"); + const sqlFormat = originalDate.utc().format(SQL_DATETIME_FORMAT); + const parsedDate = dayjs.utc(sqlFormat, SQL_DATETIME_FORMAT); + + assert.strictEqual(parsedDate.unix(), originalDate.unix()); + }); + + await t.test("Edge case: midnight timestamp", async () => { + const midnight = dayjs.utc("2025-01-01T00:00:00.000Z"); + const sqlFormat = midnight.utc().format(SQL_DATETIME_FORMAT); + + assert.strictEqual(sqlFormat, "2025-01-01 00:00:00"); + }); + + await t.test("Edge case: end of day timestamp", async () => { + const endOfDay = dayjs.utc("2025-12-31T23:59:59.999Z"); + const sqlFormat = endOfDay.utc().format(SQL_DATETIME_FORMAT); + + assert.strictEqual(sqlFormat, "2025-12-31 23:59:59"); + }); + +}); diff --git a/test/backend-test/test-migration.js b/test/backend-test/test-migration.js new file mode 100644 index 000000000..87e5ff9df --- /dev/null +++ b/test/backend-test/test-migration.js @@ -0,0 +1,133 @@ +const { describe, test } = require("node:test"); +const fs = require("fs"); +const path = require("path"); +const { GenericContainer, Wait } = require("testcontainers"); + +describe("Database Migration - Optimize Important Indexes", () => { + test("SQLite: All migrations run successfully", async () => { + const testDbPath = path.join(__dirname, "../../data/test-migration.db"); + const testDbDir = path.dirname(testDbPath); + + // Ensure data directory exists + if (!fs.existsSync(testDbDir)) { + fs.mkdirSync(testDbDir, { recursive: true }); + } + + // Clean up any existing test database + if (fs.existsSync(testDbPath)) { + fs.unlinkSync(testDbPath); + } + + // Use the same SQLite driver as the project + const Dialect = require("knex/lib/dialects/sqlite3/index.js"); + Dialect.prototype._driver = () => require("@louislam/sqlite3"); + + const knex = require("knex"); + const db = knex({ + client: Dialect, + connection: { + filename: testDbPath + }, + useNullAsDefault: true, + }); + + // Setup R (redbean) with knex instance like production code does + const { R } = require("redbean-node"); + R.setup(db); + + try { + // Use production code to initialize SQLite tables (like first run) + const { createTables } = require("../../db/knex_init_db.js"); + await createTables(); + + // Run all migrations like production code does + await R.knex.migrate.latest({ + directory: path.join(__dirname, "../../db/knex_migrations") + }); + + // Test passes if migrations complete successfully without errors + + } finally { + // Clean up + await R.knex.destroy(); + if (fs.existsSync(testDbPath)) { + fs.unlinkSync(testDbPath); + } + } + }); + + test( + "MariaDB: All migrations run successfully", + { + skip: + !!process.env.CI && + (process.platform !== "linux" || process.arch !== "x64"), + }, + async () => { + // Start MariaDB container (using MariaDB 12 to match current production) + const mariadbContainer = await new GenericContainer("mariadb:12") + .withEnvironment({ + "MYSQL_ROOT_PASSWORD": "root", + "MYSQL_DATABASE": "kuma_test", + "MYSQL_USER": "kuma", + "MYSQL_PASSWORD": "kuma" + }) + .withExposedPorts(3306) + .withWaitStrategy(Wait.forLogMessage("ready for connections", 2)) + .withStartupTimeout(120000) + .start(); + + // Wait a bit more to ensure MariaDB is fully ready + await new Promise(resolve => setTimeout(resolve, 2000)); + + const knex = require("knex"); + const knexInstance = knex({ + client: "mysql2", + connection: { + host: mariadbContainer.getHost(), + port: mariadbContainer.getMappedPort(3306), + user: "kuma", + password: "kuma", + database: "kuma_test", + connectTimeout: 60000, + }, + pool: { + min: 0, + max: 10, + acquireTimeoutMillis: 60000, + idleTimeoutMillis: 60000, + }, + }); + + // Setup R (redbean) with knex instance like production code does + const { R } = require("redbean-node"); + R.setup(knexInstance); + + try { + // Use production code to initialize MariaDB tables + const { createTables } = require("../../db/knex_init_db.js"); + await createTables(); + + // Run all migrations like production code does + await R.knex.migrate.latest({ + directory: path.join(__dirname, "../../db/knex_migrations") + }); + + // Test passes if migrations complete successfully without errors + + } finally { + // Clean up + try { + await R.knex.destroy(); + } catch (e) { + // Ignore cleanup errors + } + try { + await mariadbContainer.stop(); + } catch (e) { + // Ignore cleanup errors + } + } + } + ); +}); diff --git a/test/backend-test/test-postgres.js b/test/backend-test/test-postgres.js new file mode 100644 index 000000000..71d26d3a1 --- /dev/null +++ b/test/backend-test/test-postgres.js @@ -0,0 +1,60 @@ +const { describe, test } = require("node:test"); +const assert = require("node:assert"); +const { PostgreSqlContainer } = require("@testcontainers/postgresql"); +const { PostgresMonitorType } = require("../../server/monitor-types/postgres"); +const { UP, PENDING } = require("../../src/util"); + +describe( + "Postgres Single Node", + { + skip: + !!process.env.CI && + (process.platform !== "linux" || process.arch !== "x64"), + }, + () => { + test("Postgres is running", async () => { + // The default timeout of 30 seconds might not be enough for the container to start + const postgresContainer = await new PostgreSqlContainer( + "postgres:latest" + ) + .withStartupTimeout(60000) + .start(); + const postgresMonitor = new PostgresMonitorType(); + const monitor = { + databaseConnectionString: postgresContainer.getConnectionUri(), + }; + + const heartbeat = { + msg: "", + status: PENDING, + }; + + try { + await postgresMonitor.check(monitor, heartbeat, {}); + assert.strictEqual(heartbeat.status, UP); + } finally { + postgresContainer.stop(); + } + }); + + test("Postgres is not running", async () => { + const postgresMonitor = new PostgresMonitorType(); + const monitor = { + databaseConnectionString: "http://localhost:15432", + }; + + const heartbeat = { + msg: "", + status: PENDING, + }; + + // regex match any string + const regex = /.+/; + + await assert.rejects( + postgresMonitor.check(monitor, heartbeat, {}), + regex + ); + }); + } +); diff --git a/test/backend-test/test-rabbitmq.js b/test/backend-test/test-rabbitmq.js index 5782ef250..31f018aa9 100644 --- a/test/backend-test/test-rabbitmq.js +++ b/test/backend-test/test-rabbitmq.js @@ -2,7 +2,7 @@ const { describe, test } = require("node:test"); const assert = require("node:assert"); const { RabbitMQContainer } = require("@testcontainers/rabbitmq"); const { RabbitMqMonitorType } = require("../../server/monitor-types/rabbitmq"); -const { UP, DOWN, PENDING } = require("../../src/util"); +const { UP, PENDING } = require("../../src/util"); describe("RabbitMQ Single Node", { skip: !!process.env.CI && (process.platform !== "linux" || process.arch !== "x64"), @@ -46,8 +46,13 @@ describe("RabbitMQ Single Node", { status: PENDING, }; - await rabbitMQMonitor.check(monitor, heartbeat, {}); - assert.strictEqual(heartbeat.status, DOWN); + // regex match any string + const regex = /.+/; + + await assert.rejects( + rabbitMQMonitor.check(monitor, heartbeat, {}), + regex + ); }); }); diff --git a/test/backend-test/test-tcp.js b/test/backend-test/test-tcp.js index 3d389c154..98f168c24 100644 --- a/test/backend-test/test-tcp.js +++ b/test/backend-test/test-tcp.js @@ -1,7 +1,7 @@ const { describe, test } = require("node:test"); const assert = require("node:assert"); const { TCPMonitorType } = require("../../server/monitor-types/tcp"); -const { UP, DOWN, PENDING } = require("../../src/util"); +const { UP, PENDING } = require("../../src/util"); const net = require("net"); /** @@ -77,9 +77,10 @@ describe("TCP Monitor", () => { status: PENDING, }; - await tcpMonitor.check(monitor, heartbeat, {}); - - assert.strictEqual(heartbeat.status, DOWN); + await assert.rejects( + tcpMonitor.check(monitor, heartbeat, {}), + new Error("Connection failed") + ); }); /** @@ -104,10 +105,13 @@ describe("TCP Monitor", () => { status: PENDING, }; - await tcpMonitor.check(monitor, heartbeat, {}); + // Regex: contains with "TLS Connection failed:" or "Certificate is invalid" + const regex = /TLS Connection failed:|Certificate is invalid/; - assert.strictEqual(heartbeat.status, DOWN); - assert([ "Certificate is invalid", "TLS Connection failed:" ].some(prefix => heartbeat.msg.startsWith(prefix))); + await assert.rejects( + tcpMonitor.check(monitor, heartbeat, {}), + regex + ); }); test("TCP server with valid TLS certificate (SSL)", async t => { @@ -174,9 +178,33 @@ describe("TCP Monitor", () => { status: PENDING, }; + const regex = /does not match certificate/; + + await assert.rejects( + tcpMonitor.check(monitor, heartbeat, {}), + regex + ); + }); + test("XMPP server with valid certificate (STARTTLS)", async t => { + const tcpMonitor = new TCPMonitorType(); + + const monitor = { + hostname: "xmpp.earth", + port: 5222, + smtpSecurity: "starttls", + isEnabledExpiryNotification: () => true, + handleTlsInfo: async tlsInfo => { + return tlsInfo; + }, + }; + + const heartbeat = { + msg: "", + status: PENDING, + }; + await tcpMonitor.check(monitor, heartbeat, {}); - assert.strictEqual(heartbeat.status, DOWN); - assert([ "does not match certificate" ].some(msg => heartbeat.msg.includes(msg))); + assert.strictEqual(heartbeat.status, UP); }); }); diff --git a/test/backend-test/test-util.js b/test/backend-test/test-util.js new file mode 100644 index 000000000..470113329 --- /dev/null +++ b/test/backend-test/test-util.js @@ -0,0 +1,18 @@ +const test = require("node:test"); +const assert = require("node:assert"); + +const { getDaysRemaining, getDaysBetween } = require("../../server/util-server"); + +test("Test getDaysBetween", async (t) => { + let days = getDaysBetween(new Date(2025, 9, 7), new Date(2025, 9, 10)); + assert.strictEqual(days, 3); + days = getDaysBetween(new Date(2024, 9, 7), new Date(2025, 9, 10)); + assert.strictEqual(days, 368); +}); + +test("Test getDaysRemaining", async (t) => { + let days = getDaysRemaining(new Date(2025, 9, 7), new Date(2025, 9, 10)); + assert.strictEqual(days, 3); + days = getDaysRemaining(new Date(2025, 9, 10), new Date(2025, 9, 7)); + assert.strictEqual(days, -3); +}); diff --git a/test/backend-test/test-websocket.js b/test/backend-test/test-websocket.js index a84930bdf..33660d134 100644 --- a/test/backend-test/test-websocket.js +++ b/test/backend-test/test-websocket.js @@ -2,7 +2,7 @@ const { WebSocketServer } = require("ws"); const { describe, test } = require("node:test"); const assert = require("node:assert"); const { WebSocketMonitorType } = require("../../server/monitor-types/websocket-upgrade"); -const { UP, DOWN, PENDING } = require("../../src/util"); +const { UP, PENDING } = require("../../src/util"); describe("Websocket Test", { }, () => { @@ -19,13 +19,10 @@ describe("Websocket Test", { status: PENDING, }; - const expected = { - msg: "Unexpected server response: 200", - status: DOWN, - }; - - await websocketMonitor.check(monitor, heartbeat, {}); - assert.deepStrictEqual(heartbeat, expected); + await assert.rejects( + websocketMonitor.check(monitor, heartbeat, {}), + new Error("Unexpected server response: 200") + ); }); test("Secure Websocket", async () => { @@ -87,13 +84,10 @@ describe("Websocket Test", { status: PENDING, }; - const expected = { - msg: "Invalid Sec-WebSocket-Accept header", - status: DOWN, - }; - - await websocketMonitor.check(monitor, heartbeat, {}); - assert.deepStrictEqual(heartbeat, expected); + await assert.rejects( + websocketMonitor.check(monitor, heartbeat, {}), + new Error("Invalid Sec-WebSocket-Accept header") + ); }); test("Non compliant WS server with IgnoreSecWebsocket", async () => { @@ -153,13 +147,10 @@ describe("Websocket Test", { status: PENDING, }; - const expected = { - msg: "Unexpected server response: 200", - status: DOWN, - }; - - await websocketMonitor.check(monitor, heartbeat, {}); - assert.deepStrictEqual(heartbeat, expected); + await assert.rejects( + websocketMonitor.check(monitor, heartbeat, {}), + new Error("Unexpected server response: 200") + ); }); test("Secure Websocket with Subprotocol", async () => { @@ -176,12 +167,9 @@ describe("Websocket Test", { status: PENDING, }; - const expected = { - msg: "Server sent no subprotocol", - status: DOWN, - }; - - await websocketMonitor.check(monitor, heartbeat, {}); - assert.deepStrictEqual(heartbeat, expected); + await assert.rejects( + websocketMonitor.check(monitor, heartbeat, {}), + new Error("Server sent no subprotocol") + ); }); }); diff --git a/test/e2e/specs/monitor-form.spec.js b/test/e2e/specs/monitor-form.spec.js index b41f6ceb9..c8734fa90 100644 --- a/test/e2e/specs/monitor-form.spec.js +++ b/test/e2e/specs/monitor-form.spec.js @@ -53,7 +53,7 @@ test.describe("Monitor Form", () => { const friendlyName = "Example DNS NS"; await page.getByTestId("friendly-name-input").fill(friendlyName); - await page.getByTestId("hostname-input").fill("example.com"); + await page.getByTestId("hostname-input").fill("kuma.pet"); const resolveTypeSelect = page.getByTestId("resolve-type-select"); await resolveTypeSelect.click(); @@ -65,9 +65,9 @@ test.describe("Monitor Form", () => { await page.getByTestId("add-condition-button").click(); expect(await page.getByTestId("condition").count()).toEqual(2); // 2 explicitly added - await page.getByTestId("condition-value").nth(0).fill("a.iana-servers.net"); + await page.getByTestId("condition-value").nth(0).fill("carl.ns.cloudflare.com"); await page.getByTestId("condition-and-or").nth(0).selectOption("or"); - await page.getByTestId("condition-value").nth(1).fill("b.iana-servers.net"); + await page.getByTestId("condition-value").nth(1).fill("jean.ns.cloudflare.com"); await screenshot(testInfo, page); await page.getByTestId("save-button").click(); @@ -86,7 +86,7 @@ test.describe("Monitor Form", () => { const friendlyName = "Example DNS NS"; await page.getByTestId("friendly-name-input").fill(friendlyName); - await page.getByTestId("hostname-input").fill("example.com"); + await page.getByTestId("hostname-input").fill("kuma.pet"); const resolveTypeSelect = page.getByTestId("resolve-type-select"); await resolveTypeSelect.click(); diff --git a/test/manual-test-grpc/echo.proto b/test/manual-test-grpc/echo.proto new file mode 100644 index 000000000..39ae6a66a --- /dev/null +++ b/test/manual-test-grpc/echo.proto @@ -0,0 +1,7 @@ +syntax = "proto3"; +package echo; +service EchoService { + rpc Echo (EchoRequest) returns (EchoResponse); +} +message EchoRequest { string message = 1; } +message EchoResponse { string message = 1; } diff --git a/test/manual-test-grpc/simple-grpc-server.js b/test/manual-test-grpc/simple-grpc-server.js new file mode 100644 index 000000000..91a401e47 --- /dev/null +++ b/test/manual-test-grpc/simple-grpc-server.js @@ -0,0 +1,22 @@ +const grpc = require("@grpc/grpc-js"); +const protoLoader = require("@grpc/proto-loader"); +const packageDef = protoLoader.loadSync("echo.proto", {}); +const grpcObject = grpc.loadPackageDefinition(packageDef); +const { echo } = grpcObject; + +/** + * Echo service implementation + * @param {object} call Call object + * @param {Function} callback Callback function + * @returns {void} + */ +function Echo(call, callback) { + callback(null, { message: call.request.message }); +} + +const server = new grpc.Server(); +server.addService(echo.EchoService.service, { Echo }); +server.bindAsync("0.0.0.0:50051", grpc.ServerCredentials.createInsecure(), () => { + console.log("gRPC server running on :50051"); + server.start(); +}); diff --git a/test/mock-testdb.js b/test/mock-testdb.js new file mode 100644 index 000000000..1e6f9a9bc --- /dev/null +++ b/test/mock-testdb.js @@ -0,0 +1,27 @@ +const { sync: rimrafSync } = require("rimraf"); +const Database = require("../server/database"); + +class TestDB { + dataDir; + + constructor(dir = "./data/test") { + this.dataDir = dir; + } + + async create() { + Database.initDataDir({ "data-dir": this.dataDir }); + Database.dbConfig = { + type: "sqlite" + }; + Database.writeDBConfig(Database.dbConfig); + await Database.connect(true); + await Database.patch(); + } + + async destroy() { + await Database.close(); + this.dataDir && rimrafSync(this.dataDir); + } +} + +module.exports = TestDB; diff --git a/test/mock-webhook.js b/test/mock-webhook.js new file mode 100644 index 000000000..23bf192c7 --- /dev/null +++ b/test/mock-webhook.js @@ -0,0 +1,28 @@ +const express = require("express"); +const bodyParser = require("body-parser"); + +/** + * @param {number} port Port number + * @param {string} url Webhook URL + * @param {number} timeout Timeout + * @returns {Promise} Webhook data + */ +async function mockWebhook(port, url, timeout = 2500) { + return new Promise((resolve, reject) => { + const app = express(); + const tmo = setTimeout(() => { + server.close(); + reject({ reason: "Timeout" }); + }, timeout); + app.use(bodyParser.json()); // Middleware to parse JSON bodies + app.post(`/${url}`, (req, res) => { + res.status(200).send("OK"); + server.close(); + tmo && clearTimeout(tmo); + resolve(req.body); + }); + const server = app.listen(port); + }); +} + +module.exports = mockWebhook;