diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 82e1dab9a..d644768a1 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -12,4 +12,6 @@ f8bdfd6d5d595f22d7c0345a2eb35571343ed134 2deacd97716f5a1128b8e5b7cf6bb9bdd161b4f8 # Apply last time before automatic action -102673ed5e3e2969090ce754aa97dde88bc7377d3046b32d5fff876a4687b0896322c0a22eb4310b +102673ed5e3e2969090ce754aa97dde88bc7377d + +3046b32d5fff876a4687b0896322c0a22eb4310b diff --git a/.github/actions/build-plugin/action.yml b/.github/actions/build-plugin/action.yml index c5d65e200..4284965e4 100644 --- a/.github/actions/build-plugin/action.yml +++ b/.github/actions/build-plugin/action.yml @@ -20,25 +20,18 @@ runs: - name: Cache Composer packages id: composer-cache - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: vendor key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} restore-keys: | ${{ runner.os }}-php- - - name: Install dependencies - run: | - composer install --no-dev --prefer-dist --no-progress - shell: bash - - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v6 with: node-version-file: '.nvmrc' cache: 'npm' - - run: npm ci --legacy-peer-deps --include=dev - shell: bash - + - name: Run build script (skip zip generation) if: ${{ inputs.generate_zip == 'false' }} run: bin/build-zip.sh --skip-zip diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 485e2b752..1f1f09134 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -17,7 +17,7 @@ jobs: steps: - name: Checkout PR branch - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: ref: ${{ github.head_ref }} @@ -46,7 +46,7 @@ jobs: php vendor/bin/phpbench run tests/benchmark --report=aggregate > /tmp/pr-benchmark.txt - name: Checkout master branch - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: ref: master diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index ffe19a700..2553ce09a 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -26,12 +26,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: fetch-depth: 0 - name: Setup Node - uses: actions/setup-node@v6 + uses: actions/setup-node@v7 with: node-version: 22 cache: npm @@ -44,7 +44,7 @@ jobs: - name: Upload documentation if: github.event_name == 'push' && github.ref == 'refs/heads/master' - uses: SamKirkland/FTP-Deploy-Action@v4.3.6 + uses: SamKirkland/FTP-Deploy-Action@v4.4.0 with: server: ${{ secrets.CBPAGE_SERVER }} username: ${{ secrets.CBPAGE_USER }} diff --git a/.github/workflows/build-rc.yml b/.github/workflows/build-rc.yml index 0088935d6..fede46c33 100644 --- a/.github/workflows/build-rc.yml +++ b/.github/workflows/build-rc.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: ./.github/actions/build-plugin diff --git a/.github/workflows/compile.yml b/.github/workflows/compile.yml index 53f52dfb7..1a20ea05a 100644 --- a/.github/workflows/compile.yml +++ b/.github/workflows/compile.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-24.04 name: Check i18n coverage steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: shivammathur/setup-php@v2 with: @@ -47,7 +47,7 @@ jobs: needs: i18n-coverage steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 with: ref: ${{ github.ref }} # checkout the latest commit so that we can push changes @@ -55,7 +55,7 @@ jobs: with: php-version: '8.1' - - uses: actions/setup-node@v6 + - uses: actions/setup-node@v7 with: node-version-file: '.nvmrc' cache: 'npm' diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 853bcfffb..2f478fe7e 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -27,7 +27,7 @@ jobs: # If you do not check out your code, Copilot will do this for you. steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Set up MySQL run: | diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 48398af57..d20a3abc9 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -36,7 +36,7 @@ jobs: - {name: 'trunk', version: 'WordPress/WordPress#master'} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: ./.github/actions/build-plugin @@ -44,12 +44,16 @@ jobs: shell: bash run: npm -g i @wordpress/env - - name: Overwrite PHP versions & core for wp-env - if: matrix.core.version != 'null' - run: jq '. + {"phpVersion":"${{ matrix.php }}","core":"${{ matrix.core.version }}"}' tests/cypress/wordpress-files/e2e-override.json > .wp-env.override.json + - name: Overwrite PHP version & core for wp-env + run: > + jq + --arg php "${{ matrix.php }}" + --arg core "${{ matrix.core.version }}" + '. + {"phpVersion": $php} + (if $core == "null" then {} else {"core": $core} end)' + tests/cypress/wordpress-files/e2e-override.json > .wp-env.test.override.json - name: setup wp env - run: npm run env:start + run: npm run env:test:start - name: install test data for e2e test run: npm run cypress:setup @@ -69,15 +73,23 @@ jobs: - name: Enable API run: | - wp-env run tests-cli wp option patch insert commonsbooking_options_api api-activated on - wp-env run tests-cli wp option patch insert commonsbooking_options_api apikey_not_required on + wp-env --config=.wp-env.test.json run cli wp option patch insert commonsbooking_options_api api-activated on + wp-env --config=.wp-env.test.json run cli wp option patch insert commonsbooking_options_api apikey_not_required on - name: Checkout GBFS validator - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: repository: MobilityData/gbfs-validator path: gbfs-validator + - name: Cache GBFS validator dependencies + uses: actions/cache@v6 + with: + path: gbfs-validator/node_modules + key: ${{ runner.os }}-gbfs-validator-${{ hashFiles('gbfs-validator/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-gbfs-validator- + - name: Install GBFS validator dependencies working-directory: gbfs-validator run: yarn diff --git a/.github/workflows/phpcbf-check.yml b/.github/workflows/phpcbf-check.yml index eab686670..0406c7514 100644 --- a/.github/workflows/phpcbf-check.yml +++ b/.github/workflows/phpcbf-check.yml @@ -16,12 +16,12 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Set up PHP uses: shivammathur/setup-php@v2 with: - php-version: '8.1' # Adjust this to your PHP version + php-version: '8.1' extensions: uopz diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index e79a98618..82e25427e 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -25,7 +25,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 # TODO Use the composer action below - uses: shivammathur/setup-php@v2 @@ -44,7 +44,7 @@ jobs: run: | composer dump-autoload -o - #- uses: actions/checkout@v6 + #- uses: actions/checkout@v7 #- uses: php-actions/composer@v6 - name: PHPStan Static Analysis diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index c26fa59a5..442861e46 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -38,7 +38,7 @@ jobs: - { name: 'trunk', version: 'trunk' } steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Set up MySQL run: | @@ -53,13 +53,12 @@ jobs: - name: Install SVN run: sudo apt install -y subversion - - name: Validate composer.json and composer.lock run: composer validate - name: Cache Composer packages id: composer-cache - uses: actions/cache@v5 + uses: actions/cache@v6 with: path: vendor key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} @@ -84,7 +83,7 @@ jobs: php vendor/bin/phpunit - name: Upload coverage reports to Codecov - uses: codecov/codecov-action@v6 + uses: codecov/codecov-action@v7 with: token: ${{ secrets.CODECOV_TOKEN }} files: ./build/logs/clover.xml diff --git a/.github/workflows/prettier.yml b/.github/workflows/prettier.yml index 8c1b2cf0c..ed89b122d 100644 --- a/.github/workflows/prettier.yml +++ b/.github/workflows/prettier.yml @@ -7,8 +7,10 @@ jobs: prettier: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - uses: actions/setup-node@v6 + - uses: actions/checkout@v7 + - uses: actions/setup-node@v7 + with: + node-version-file: '.nvmrc' - run: | yarn yarn prettier . --check diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8da28da87..d2903dd3f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,9 +8,11 @@ jobs: publish: name: New Release runs-on: ubuntu-24.04 + permissions: + contents: write steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: ./.github/actions/build-plugin @@ -34,11 +36,6 @@ jobs: SLUG: commonsbooking # optional, remove if GitHub repo name matches SVN slug, including capitalization - name: Upload release asset - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + uses: softprops/action-gh-release@v3 with: - upload_url: ${{ github.event.release.upload_url }} - asset_path: ${{ steps.deploy.outputs.zip-path }} - asset_name: ${{ github.event.repository.name }}.zip - asset_content_type: application/zip + files: ${{ steps.deploy.outputs.zip-path }} \ No newline at end of file diff --git a/.github/workflows/wpcs.yml b/.github/workflows/wpcs.yml index 755b720b4..d31045292 100644 --- a/.github/workflows/wpcs.yml +++ b/.github/workflows/wpcs.yml @@ -16,7 +16,7 @@ jobs: name: WPCS runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Install dependencies run: composer install --prefer-dist --no-progress --ignore-platform-reqs - name: WPCS check diff --git a/.github/workflows/zip-pr.yml b/.github/workflows/zip-pr.yml index 65bde2e21..40cde4f9a 100644 --- a/.github/workflows/zip-pr.yml +++ b/.github/workflows/zip-pr.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 with: fetch-depth: 0 # Important for getting full commit history @@ -29,7 +29,7 @@ jobs: - name: Upload zip if: ${{ !startsWith(github.head_ref, 'dependabot') }} - uses: SamKirkland/FTP-Deploy-Action@v4.3.6 + uses: SamKirkland/FTP-Deploy-Action@v4.4.0 with: exclude: | ** diff --git a/.nvmrc b/.nvmrc index 953490f51..eb6ead3cf 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v20.20.0 +v24.16.0 diff --git a/.wp-env.json b/.wp-env.json index 472d450d2..4e738e380 100644 --- a/.wp-env.json +++ b/.wp-env.json @@ -1,6 +1,6 @@ { "phpVersion" : "8.1", - "core" : "Wordpress/Wordpress#6.9", + "core" : "Wordpress/Wordpress#7.0", "plugins" : [ ".", "https://downloads.wordpress.org/plugin/wp-crontrol.zip", @@ -11,7 +11,7 @@ "https://downloads.wordpress.org/plugin/disable-welcome-messages-and-tips.zip" ], "port" : 1000, - "testsPort" : 1001, + "testsEnvironment" : false, "config" : { "WP_DEBUG" : true, "WP_DEBUG_LOG" : true, @@ -19,17 +19,5 @@ }, "themes" : [ "flegfleg/kasimir-theme" - ], - "env" : { - "tests" : { - "mappings" : { - "wp-content/plugins/commonsbooking" : "." - }, - "config" : { - "WP_DEBUG" : true, - "WP_DEBUG_LOG" : true, - "WP_DEBUG_DISPLAY" : false - } - } - } + ] } diff --git a/.wp-env.test.json b/.wp-env.test.json new file mode 100644 index 000000000..463c34170 --- /dev/null +++ b/.wp-env.test.json @@ -0,0 +1,23 @@ +{ + "phpVersion" : "8.1", + "core" : "Wordpress/Wordpress#6.9", + "plugins" : [ + ".", + "https://downloads.wordpress.org/plugin/wp-crontrol.zip", + "https://downloads.wordpress.org/plugin/wordpress-importer.zip", + "https://downloads.wordpress.org/plugin/query-monitor.zip", + "https://downloads.wordpress.org/plugin/wp-mail-logging.zip", + "https://downloads.wordpress.org/plugin/jsm-show-post-meta.zip", + "https://downloads.wordpress.org/plugin/disable-welcome-messages-and-tips.zip" + ], + "port" : 1001, + "testsEnvironment" : false, + "config" : { + "WP_DEBUG" : true, + "WP_DEBUG_LOG" : true, + "WP_DEBUG_DISPLAY" : false + }, + "themes" : [ + "flegfleg/kasimir-theme" + ] +} diff --git a/Readme.md b/Readme.md index 3aace4a9e..e6fbc7f0e 100644 --- a/Readme.md +++ b/Readme.md @@ -6,12 +6,15 @@ # CommonsBooking -Contributors: wielebenwirteam, m0rb, flegfleg, chriwen -Donate link: https://www.wielebenwir.de/verein/unterstutzen -License: GPLv2 or later -License URI: http://www.gnu.org/licenses/gpl-2.0.html +**Contributors**: wielebenwirteam, m0rb, flegfleg, chriwen, hansmorb, datengraben -CommonsBooking is a plugin for the management and booking of common goods. This plugin provides associations, groups, and individuals with the ability to share items (such as cargo bikes and tools) among users. It is based on the concept of Commons, where resources are shared for the benefit of the community. +**Donate link**: https://www.wielebenwir.de/verein/unterstutzen + +**License**: GPLv2 or later + +**License URI**: http://www.gnu.org/licenses/gpl-2.0.html + +CommonsBooking is a plugin for the management and booking of common goods. This plugin gives associations, groups and individuals the ability to share items (e.g. cargo bikes, tools) with users. It is based on the idea of the commons and sharing resources for the benefit of the community. ## Links @@ -86,6 +89,7 @@ First, we have to install the necessary dependencies and packages: We can do thi npm run start ``` `npm run start` runs `composer install`, `npm install` and then builds assets via `grunt dist`. +This might take a while, as dependencies are downloaded and namespaces are prefixed using Strauss. The most easy way to start hacking WordPress plugins in general (if you have no other development environment set up) is using [wp-env](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-env/). Install it and it's dependencies (mainly Docker) and run this to start the enviroment: ``` @@ -105,14 +109,14 @@ To test the code you first run the [preparation scripts](https://github.com/wp-c bash bin/install-wp-tests.sh wordpress root password 127.0.0.1:49153 latest ``` -Testing the plugin code via `phpunit`. At the moment it works only with a manually downloaded phar. We are using PHPUnit 9 and PHP7.4 for the automated tests. The tests might fail if you are using a different version. +Testing the plugin code via `phpunit`. We are using PHPUnit 9, because it is the latest version currently compatible with the WordPress testing suite. ``` -php ~/phpunit.phar --bootstrap tests/php/bootstrap.php +php vendor/bin/phpunit --bootstrap tests/php/bootstrap.php ``` E2E (end to end) tests are written in [cypress](https://www.cypress.io/). To run them you need to install cypress and start the wordpress environment: ```bash -npm run env:start +npm run env:test:start ``` Now, install the test data needed for the tests: ```bash diff --git a/assets/admin/js/src/timeframe.js b/assets/admin/js/src/timeframe.js index 632aa565d..88561efa0 100644 --- a/assets/admin/js/src/timeframe.js +++ b/assets/admin/js/src/timeframe.js @@ -170,7 +170,7 @@ * Currently only for holidays, holidays used to only have one assignable single selection. */ const migrateSingleSelection = () => { - if (typeInput.val() != HOLIDAYS_ID) { + if (typeInput.val() != HOLIDAYS_ID || typeInput.val() != REPAIR_ID) { return; } // get single selection @@ -222,7 +222,7 @@ } //we migrate the single selection to the multiselect (new holiday timeframes do not have a single selection anymore) - if (selectedType == HOLIDAYS_ID) { + if (selectedType == HOLIDAYS_ID || selectedType == REPAIR_ID) { itemSelectionInput.show(); locationSelectionInput.show(); migrateSingleSelection(); @@ -244,7 +244,7 @@ const handleLocationSelection = function () { const selectedType = $('option:selected', typeInput).val(); //disable the mass selection for all timeframes except holidays - if (selectedType == HOLIDAYS_ID) { + if (selectedType == HOLIDAYS_ID || selectedType == REPAIR_ID) { singleLocationSelection.hide(); //handle different selection types const selectedOption = $('option:selected', locationSelectionInput).val(); @@ -275,7 +275,7 @@ const handleItemSelection = function () { const selectedType = $('option:selected', typeInput).val(); //disable the mass selection for all timeframes except holidays (for now) - if (selectedType == HOLIDAYS_ID) { + if (selectedType == HOLIDAYS_ID || selectedType == REPAIR_ID) { singleItemSelection.hide(); //handle different selection types const selectedOption = $('option:selected', itemSelectionInput).val(); diff --git a/assets/public/js/src/lib/litepicker.js b/assets/public/js/src/lib/litepicker.js index 64f0e754a..3d0a3a41c 100644 --- a/assets/public/js/src/lib/litepicker.js +++ b/assets/public/js/src/lib/litepicker.js @@ -247,7 +247,7 @@ ) t.styleSheet.cssText = o; else { - for (; t.firstChild; ) t.removeChild(t.firstChild); + for (; t.firstChild;) t.removeChild(t.firstChild); t.appendChild(document.createTextNode(o)); } } @@ -826,7 +826,7 @@ this.datePicked[0].getTime() < k.getTime() && u.push(k); } - for (; h > 0; ) { + for (; h > 0;) { ((h -= 1), (c = c.add(1, 'day'))); for (var D = 0, v = u; D < v.length; D++) v[D].getTime() === c.getTime() && @@ -1113,7 +1113,7 @@ if (/^-?\d{10,}$/.test(e)) return t.getDateZeroTime(new Date(Number(e))); if ('string' == typeof e) { - for (var n = [], s = null; null != (s = t.regex.exec(i)); ) + for (var n = [], s = null; null != (s = t.regex.exec(i));) '\\' !== s[1] && n.push(s); if (n.length) { var a = { @@ -1510,7 +1510,7 @@ }), (t.prototype.format = function (e, i) { void 0 === i && (i = 'en-US'); - for (var o = '', n = [], s = null; null != (s = t.regex.exec(e)); ) + for (var o = '', n = [], s = null; null != (s = t.regex.exec(e));) '\\' !== s[1] && n.push(s); if (n.length) { n[0].index > 0 && (o += e.substring(0, n[0].index)); diff --git a/bin/setup-cypress-env.sh b/bin/setup-cypress-env.sh index 0ca73a05c..24a72e5d3 100755 --- a/bin/setup-cypress-env.sh +++ b/bin/setup-cypress-env.sh @@ -1,8 +1,8 @@ #!/bin/bash -wp-env run tests-cli wp plugin install --activate wordpress-importer +wp-env --config=.wp-env.test.json run cli wp plugin install --activate wordpress-importer # Install our example posts from a WP export file -wp-env run tests-cli wp import /var/www/html/wp-content/plugins/commonsbooking/tests/cypress/wordpress-files/content-example.xml --authors=create +wp-env --config=.wp-env.test.json run cli wp import /var/www/html/wp-content/plugins/commonsbooking/tests/cypress/wordpress-files/content-example.xml --authors=create # Switch to Kasimir theme -wp-env run tests-cli wp theme activate kasimir-theme +wp-env --config=.wp-env.test.json run cli wp theme activate kasimir-theme # Create subscriber with username "subscriber" and password "password" -wp-env run tests-cli wp user create subscriber sub@sub.de --role=subscriber --user_pass=password +wp-env --config=.wp-env.test.json run cli wp user create subscriber sub@sub.de --role=subscriber --user_pass=password diff --git a/commonsbooking.php b/commonsbooking.php index 6d9c4884e..a300ea23d 100644 --- a/commonsbooking.php +++ b/commonsbooking.php @@ -2,7 +2,7 @@ /** * Plugin Name: Commons Booking - * Version: 2.10.10 + * Version: 2.11 * Requires at least: 5.2 * Requires PHP: 8.1 * Plugin URI: https://commonsbooking.org @@ -16,7 +16,7 @@ */ defined( 'ABSPATH' ) || die( 'Thanks for visiting' ); -define( 'COMMONSBOOKING_VERSION', '2.10.10' ); +define( 'COMMONSBOOKING_VERSION', '2.11' ); define( 'COMMONSBOOKING_VERSION_COMMENT', '' ); // Empty for release - Used to mark development versions define( 'COMMONSBOOKING_PLUGIN_SLUG', 'commonsbooking' ); define( 'COMMONSBOOKING_MENU_SLUG', COMMONSBOOKING_PLUGIN_SLUG . '-menu' ); diff --git a/composer.json b/composer.json index 4416b5a2e..ba48bef23 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "wielebenwir/commonsbooking", "description": "~", "homepage": "https://commonsbooking.org", - "version": "2.10.10", + "version": "2.11", "type": "wordpress-plugin", "license": "GPL-2.0-or-later", "prefer-stable": true, @@ -78,7 +78,7 @@ "@prefix-namespaces" ], "prefix-namespaces": [ - "sh -c 'test -f ./bin/strauss.phar || curl -o bin/strauss.phar -L -C - https://github.com/BrianHenryIE/strauss/releases/download/0.26.5/strauss.phar'", + "sh -c 'test -f ./bin/strauss.phar || curl -o bin/strauss.phar -L -C - https://github.com/BrianHenryIE/strauss/releases/download/0.28.1/strauss.phar'", "@php bin/strauss.phar --info", "@composer dump-autoload" ] diff --git a/composer.lock b/composer.lock index c25b1dba2..91928c57e 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "2faad4821957e84dda680c7d58ef1488", + "content-hash": "f799e9654eb730088e62c4f40e997bb4", "packages": [ { "name": "clue/stream-filter", @@ -74,26 +74,23 @@ }, { "name": "cmb2/cmb2", - "version": "v2.11.0", + "version": "v2.12.0", "source": { "type": "git", "url": "https://github.com/CMB2/CMB2.git", - "reference": "2847828b5cce1b48d09427ee13e6f7c752704468" + "reference": "9a3686d42539ee3c1113bd09623f4ffbbee94397" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/CMB2/CMB2/zipball/2847828b5cce1b48d09427ee13e6f7c752704468", - "reference": "2847828b5cce1b48d09427ee13e6f7c752704468", + "url": "https://api.github.com/repos/CMB2/CMB2/zipball/9a3686d42539ee3c1113bd09623f4ffbbee94397", + "reference": "9a3686d42539ee3c1113bd09623f4ffbbee94397", "shasum": "" }, "require": { "php": ">7.4" }, "require-dev": { - "apigen/apigen": "4.1.2", - "awesomemotive/am-cli-tools": ">=1.3.7", - "nette/utils": "2.5.3", - "phpunit/phpunit": "^6.5", + "phpunit/phpunit": "^9.6", "yoast/phpunit-polyfills": "^1.1" }, "suggest": { @@ -129,7 +126,7 @@ "issues": "https://github.com/CMB2/CMB2/issues", "source": "http://wordpress.org/support/plugin/cmb2" }, - "time": "2024-04-02T19:30:07+00:00" + "time": "2026-05-31T02:21:57+00:00" }, { "name": "ed-itsolutions/cmb2-field-ajax-search", @@ -978,16 +975,16 @@ }, { "name": "phpmailer/phpmailer", - "version": "v7.0.2", + "version": "v7.1.1", "source": { "type": "git", "url": "https://github.com/PHPMailer/PHPMailer.git", - "reference": "ebf1655bd5b99b3f97e1a3ec0a69e5f4cd7ea088" + "reference": "1bc1716a507a65e039d4ac9d9adebbbd0d346e15" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/ebf1655bd5b99b3f97e1a3ec0a69e5f4cd7ea088", - "reference": "ebf1655bd5b99b3f97e1a3ec0a69e5f4cd7ea088", + "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/1bc1716a507a65e039d4ac9d9adebbbd0d346e15", + "reference": "1bc1716a507a65e039d4ac9d9adebbbd0d346e15", "shasum": "" }, "require": { @@ -1048,7 +1045,7 @@ "description": "PHPMailer is a full-featured email creation and transfer class for PHP", "support": { "issues": "https://github.com/PHPMailer/PHPMailer/issues", - "source": "https://github.com/PHPMailer/PHPMailer/tree/v7.0.2" + "source": "https://github.com/PHPMailer/PHPMailer/tree/v7.1.1" }, "funding": [ { @@ -1056,7 +1053,7 @@ "type": "github" } ], - "time": "2026-01-09T18:02:33+00:00" + "time": "2026-05-18T08:06:14+00:00" }, { "name": "psr/cache", @@ -1452,16 +1449,16 @@ }, { "name": "symfony/cache", - "version": "v5.4.40", + "version": "v5.4.52", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "89005bc368ca02ed0433c592e4d27670d0844a66" + "reference": "03b191dda148c490b5b3929eaac827ee64f1d421" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/89005bc368ca02ed0433c592e4d27670d0844a66", - "reference": "89005bc368ca02ed0433c592e4d27670d0844a66", + "url": "https://api.github.com/repos/symfony/cache/zipball/03b191dda148c490b5b3929eaac827ee64f1d421", + "reference": "03b191dda148c490b5b3929eaac827ee64f1d421", "shasum": "" }, "require": { @@ -1529,7 +1526,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v5.4.40" + "source": "https://github.com/symfony/cache/tree/v5.4.52" }, "funding": [ { @@ -1540,12 +1537,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-05-31T14:33:22+00:00" + "time": "2026-05-15T06:40:15+00:00" }, { "name": "symfony/cache-contracts", @@ -1628,16 +1629,16 @@ }, { "name": "symfony/deprecation-contracts", - "version": "v3.6.0", + "version": "v3.7.1", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" + "reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", - "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/f3202fa1b5097b0af062dc978b32ecf63404e31d", + "reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d", "shasum": "" }, "require": { @@ -1650,7 +1651,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.6-dev" + "dev-main": "3.7-dev" } }, "autoload": { @@ -1675,7 +1676,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.7.1" }, "funding": [ { @@ -1686,12 +1687,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-25T14:21:43+00:00" + "time": "2026-06-05T06:23:12+00:00" }, { "name": "symfony/http-client", @@ -1942,7 +1947,7 @@ }, { "name": "symfony/polyfill-php73", - "version": "v1.33.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", @@ -1998,7 +2003,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.37.0" }, "funding": [ { @@ -2022,16 +2027,16 @@ }, { "name": "symfony/polyfill-php80", - "version": "v1.33.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608" + "reference": "dfb55726c3a76ea3b6459fcfda1ec2d80a682411" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608", - "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dfb55726c3a76ea3b6459fcfda1ec2d80a682411", + "reference": "dfb55726c3a76ea3b6459fcfda1ec2d80a682411", "shasum": "" }, "require": { @@ -2082,7 +2087,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.37.0" }, "funding": [ { @@ -2102,7 +2107,7 @@ "type": "tidelift" } ], - "time": "2025-01-02T08:10:11+00:00" + "time": "2026-04-10T16:19:22+00:00" }, { "name": "symfony/polyfill-php83", @@ -2186,16 +2191,16 @@ }, { "name": "symfony/service-contracts", - "version": "v3.6.1", + "version": "v3.7.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43" + "reference": "c0a284bab1ed8aa0417e3d69250ab437739563a0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43", - "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/c0a284bab1ed8aa0417e3d69250ab437739563a0", + "reference": "c0a284bab1ed8aa0417e3d69250ab437739563a0", "shasum": "" }, "require": { @@ -2213,7 +2218,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.6-dev" + "dev-main": "3.7-dev" } }, "autoload": { @@ -2249,7 +2254,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.6.1" + "source": "https://github.com/symfony/service-contracts/tree/v3.7.1" }, "funding": [ { @@ -2269,28 +2274,30 @@ "type": "tidelift" } ], - "time": "2025-07-15T11:30:57+00:00" + "time": "2026-06-16T09:55:08+00:00" }, { "name": "symfony/var-exporter", - "version": "v5.4.40", + "version": "v6.4.37", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "6a13d37336d512927986e09f19a4bed24178baa6" + "reference": "34f6957deffacabd1b1c579a312daa481e3e99ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/6a13d37336d512927986e09f19a4bed24178baa6", - "reference": "6a13d37336d512927986e09f19a4bed24178baa6", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/34f6957deffacabd1b1c579a312daa481e3e99ca", + "reference": "34f6957deffacabd1b1c579a312daa481e3e99ca", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/polyfill-php80": "^1.16" + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3" }, "require-dev": { - "symfony/var-dumper": "^4.4.9|^5.0.9|^6.0" + "symfony/property-access": "^6.4|^7.0", + "symfony/serializer": "^6.4|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0" }, "type": "library", "autoload": { @@ -2323,10 +2330,12 @@ "export", "hydrate", "instantiate", + "lazy-loading", + "proxy", "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v5.4.40" + "source": "https://github.com/symfony/var-exporter/tree/v6.4.37" }, "funding": [ { @@ -2337,12 +2346,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-05-31T14:33:22+00:00" + "time": "2026-04-14T12:12:40+00:00" }, { "name": "willdurand/geocoder", @@ -2410,29 +2423,29 @@ "packages-dev": [ { "name": "dealerdirect/phpcodesniffer-composer-installer", - "version": "v1.1.2", + "version": "v1.2.1", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/composer-installer.git", - "reference": "e9cf5e4bbf7eeaf9ef5db34938942602838fc2b1" + "reference": "963f0c67bffde0eac41b56be71ac0e8ba132f0bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/e9cf5e4bbf7eeaf9ef5db34938942602838fc2b1", - "reference": "e9cf5e4bbf7eeaf9ef5db34938942602838fc2b1", + "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/963f0c67bffde0eac41b56be71ac0e8ba132f0bd", + "reference": "963f0c67bffde0eac41b56be71ac0e8ba132f0bd", "shasum": "" }, "require": { "composer-plugin-api": "^2.2", "php": ">=5.4", - "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0" + "squizlabs/php_codesniffer": "^3.1.0 || ^4.0" }, "require-dev": { "composer/composer": "^2.2", "ext-json": "*", "ext-zip": "*", "php-parallel-lint/php-parallel-lint": "^1.4.0", - "phpcompatibility/php-compatibility": "^9.0", + "phpcompatibility/php-compatibility": "^9.0 || ^10.0.0@dev", "yoast/phpunit-polyfills": "^1.0" }, "type": "composer-plugin", @@ -2502,7 +2515,7 @@ "type": "thanks_dev" } ], - "time": "2025-07-17T20:45:56+00:00" + "time": "2026-05-06T08:26:05+00:00" }, { "name": "doctrine/annotations", @@ -3513,27 +3526,27 @@ }, { "name": "phpcsstandards/phpcsextra", - "version": "1.4.0", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHPCSExtra.git", - "reference": "fa4b8d051e278072928e32d817456a7fdb57b6ca" + "reference": "b598aa890815b8df16363271b659d73280129101" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHPCSExtra/zipball/fa4b8d051e278072928e32d817456a7fdb57b6ca", - "reference": "fa4b8d051e278072928e32d817456a7fdb57b6ca", + "url": "https://api.github.com/repos/PHPCSStandards/PHPCSExtra/zipball/b598aa890815b8df16363271b659d73280129101", + "reference": "b598aa890815b8df16363271b659d73280129101", "shasum": "" }, "require": { "php": ">=5.4", - "phpcsstandards/phpcsutils": "^1.1.0", - "squizlabs/php_codesniffer": "^3.13.0 || ^4.0" + "phpcsstandards/phpcsutils": "^1.2.0", + "squizlabs/php_codesniffer": "^3.13.5 || ^4.0.1" }, "require-dev": { "php-parallel-lint/php-console-highlighter": "^1.0", "php-parallel-lint/php-parallel-lint": "^1.4.0", - "phpcsstandards/phpcsdevcs": "^1.1.6", + "phpcsstandards/phpcsdevcs": "^1.2.0", "phpcsstandards/phpcsdevtools": "^1.2.1", "phpunit/phpunit": "^4.5 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" }, @@ -3591,32 +3604,32 @@ "type": "thanks_dev" } ], - "time": "2025-06-14T07:40:39+00:00" + "time": "2025-11-12T23:06:57+00:00" }, { "name": "phpcsstandards/phpcsutils", - "version": "1.1.0", + "version": "1.2.2", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHPCSUtils.git", - "reference": "65355670ac17c34cd235cf9d3ceae1b9252c4dad" + "reference": "c216317e96c8b3f5932808f9b0f1f7a14e3bbf55" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHPCSUtils/zipball/65355670ac17c34cd235cf9d3ceae1b9252c4dad", - "reference": "65355670ac17c34cd235cf9d3ceae1b9252c4dad", + "url": "https://api.github.com/repos/PHPCSStandards/PHPCSUtils/zipball/c216317e96c8b3f5932808f9b0f1f7a14e3bbf55", + "reference": "c216317e96c8b3f5932808f9b0f1f7a14e3bbf55", "shasum": "" }, "require": { "dealerdirect/phpcodesniffer-composer-installer": "^0.4.1 || ^0.5 || ^0.6.2 || ^0.7 || ^1.0", "php": ">=5.4", - "squizlabs/php_codesniffer": "^3.13.0 || ^4.0" + "squizlabs/php_codesniffer": "^3.13.5 || ^4.0.1" }, "require-dev": { "ext-filter": "*", "php-parallel-lint/php-console-highlighter": "^1.0", "php-parallel-lint/php-parallel-lint": "^1.4.0", - "phpcsstandards/phpcsdevcs": "^1.1.6", + "phpcsstandards/phpcsdevcs": "^1.2.0", "yoast/phpunit-polyfills": "^1.1.0 || ^2.0.0 || ^3.0.0" }, "type": "phpcodesniffer-standard", @@ -3684,7 +3697,7 @@ "type": "thanks_dev" } ], - "time": "2025-06-12T04:32:33+00:00" + "time": "2025-12-08T14:27:58+00:00" }, { "name": "phpstan/extension-installer", @@ -3736,11 +3749,11 @@ }, { "name": "phpstan/phpstan", - "version": "2.1.44", + "version": "2.2.5", "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/4a88c083c668b2c364a425c9b3171b2d9ea5d218", - "reference": "4a88c083c668b2c364a425c9b3171b2d9ea5d218", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/909c1e5fef7989ac0d0c1c5c42e32a5c4f6198a0", + "reference": "909c1e5fef7989ac0d0c1c5c42e32a5c4f6198a0", "shasum": "" }, "require": { @@ -3763,6 +3776,17 @@ "license": [ "MIT" ], + "authors": [ + { + "name": "Ondřej Mirtes" + }, + { + "name": "Markus Staab" + }, + { + "name": "Vincent Langlet" + } + ], "description": "PHPStan - PHP Static Analysis Tool", "keywords": [ "dev", @@ -3785,7 +3809,7 @@ "type": "github" } ], - "time": "2026-03-25T17:34:21+00:00" + "time": "2026-07-05T06:31:06+00:00" }, { "name": "phpunit/php-code-coverage", @@ -6314,16 +6338,16 @@ }, { "name": "wp-coding-standards/wpcs", - "version": "3.2.0", + "version": "3.4.0", "source": { "type": "git", "url": "https://github.com/WordPress/WordPress-Coding-Standards.git", - "reference": "d2421de7cec3274ae622c22c744de9a62c7925af" + "reference": "469c18ceab4d642b15bad4c65ebf3b307bfd55ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/d2421de7cec3274ae622c22c744de9a62c7925af", - "reference": "d2421de7cec3274ae622c22c744de9a62c7925af", + "url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/469c18ceab4d642b15bad4c65ebf3b307bfd55ab", + "reference": "469c18ceab4d642b15bad4c65ebf3b307bfd55ab", "shasum": "" }, "require": { @@ -6331,17 +6355,17 @@ "ext-libxml": "*", "ext-tokenizer": "*", "ext-xmlreader": "*", - "php": ">=5.4", - "phpcsstandards/phpcsextra": "^1.4.0", - "phpcsstandards/phpcsutils": "^1.1.0", - "squizlabs/php_codesniffer": "^3.13.0" + "php": ">=7.2", + "phpcsstandards/phpcsextra": "^1.5.0", + "phpcsstandards/phpcsutils": "^1.2.2", + "squizlabs/php_codesniffer": "^3.13.5" }, "require-dev": { "php-parallel-lint/php-console-highlighter": "^1.0.0", "php-parallel-lint/php-parallel-lint": "^1.4.0", - "phpcompatibility/php-compatibility": "^9.0", + "phpcompatibility/php-compatibility": "^10.0.0@dev", "phpcsstandards/phpcsdevtools": "^1.2.0", - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^8.0 || ^9.0" }, "suggest": { "ext-iconv": "For improved results", @@ -6376,7 +6400,7 @@ "type": "custom" } ], - "time": "2025-07-24T20:08:31+00:00" + "time": "2026-07-16T13:05:29+00:00" }, { "name": "yoast/phpunit-polyfills", diff --git a/docs/.vitepress/components/AnnouncementBanner.vue b/docs/.vitepress/components/AnnouncementBanner.vue new file mode 100644 index 000000000..13e0cf076 --- /dev/null +++ b/docs/.vitepress/components/AnnouncementBanner.vue @@ -0,0 +1,75 @@ + + + + + diff --git a/docs/.vitepress/components/ExpandAll.vue b/docs/.vitepress/components/ExpandAll.vue new file mode 100644 index 000000000..85c12a95b --- /dev/null +++ b/docs/.vitepress/components/ExpandAll.vue @@ -0,0 +1,53 @@ + + + + + diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index cbf4fdbc8..ab735d895 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -4,7 +4,7 @@ import { defineConfig, type DefaultTheme } from 'vitepress' const require = createRequire(import.meta.url) const pkg = require('../../package.json') -const COMMONSBOOKING_VERSION_STRING = '2.10.10'; +const COMMONSBOOKING_VERSION_STRING = '2.11'; // https://vitepress.dev/reference/site-config export default defineConfig({ @@ -273,19 +273,7 @@ export function sidebarDocs_de(): DefaultTheme.SidebarItem[] { { text: 'Häufige Fragen (Version 0.9.x)', link: 'faq' } ] }, - { - text: 'Häufige Fragen (FAQ)', base: '/de/documentation/faq/', - link: '/', - collapsed: true, - items: [ - { text: 'Die Seite ist sehr langsam', link: 'site-slow' }, - { text: 'Probleme und Antworten', link: 'problems-and-answers' }, - { text: 'Wie bekomme ich den Buchungskommentar ...', link: 'booking-comment-emails' }, - { text: 'Kann ich Zahlenschloss-Codes in E-Mails einfügen?', link: 'lock-codes-email' }, - { text: 'Artikeldetailseite übersichtlicher gestalten', link: 'organise-article-page' }, - { text: 'Wie verhindere ich Spam Registrierungen', link: 'avoid-spam-registrations'} - ] - }, + { text: 'Häufige Fragen (FAQ)', link: '/de/documentation/faq/', items: [] }, ] } @@ -395,19 +383,7 @@ export function sidebarDocs_en(): DefaultTheme.SidebarItem[] { { text: 'Overview of releases and planned further development', link: 'release-overview' } ] }, - { - text: 'Frequently Asked Questions (FAQ)', base: '/en/documentation/faq/', - link: '/', - collapsed: true, - items: [ - { text: 'The site is very slow', link: 'site-slow' }, - { text: 'Problems and answers', link: 'problems-and-answers' }, - { text: 'How do I show the booking comment on the page and in the email?', link: 'booking-comment-emails' }, - { text: 'How do I show lock codes in emails?', link: 'lock-codes-email' }, - { text: 'How can I make the item detail page clearer?', link: 'organise-article-page' }, - { text: 'How do I prevent spam registrations?', link: 'avoid-spam-registrations'} - ] - }, + { text: 'Frequently Asked Questions (FAQ)', link: '/en/documentation/faq/', items: [] }, ] } diff --git a/docs/.vitepress/theme/index.js b/docs/.vitepress/theme/index.js index fd81d720f..293df5935 100644 --- a/docs/.vitepress/theme/index.js +++ b/docs/.vitepress/theme/index.js @@ -1,25 +1,28 @@ // .vitepress/theme/index.js +import { h, onMounted } from 'vue' import DefaultTheme from 'vitepress/theme' import './custom.css' -import { onMounted } from 'vue'; -import mediumZoom from 'medium-zoom'; -import { useData } from 'vitepress'; +import mediumZoom from 'medium-zoom' +import { useData } from 'vitepress' +import AnnouncementBanner from '../components/AnnouncementBanner.vue' export default { - ...DefaultTheme, - setup() { - const { page } = useData(); - - onMounted(() => { - const LOCALE_STORAGE_KEY = 'cb-doc-locale'; - const path = window.location.pathname; - const locale = path.startsWith('/en/') ? '/en/' : path.startsWith('/de/') ? '/de/' : '/de/'; - - // Persist the currently viewed locale so root can reuse the choice later - localStorage.setItem(LOCALE_STORAGE_KEY, locale); - - // Keep zoom working across locales - mediumZoom('[data-zoomable]', { background: 'var(--vp-c-bg)' }); - }); - }, + ...DefaultTheme, + Layout() { + return h(DefaultTheme.Layout, null, { + 'home-hero-before': () => h(AnnouncementBanner), + }) + }, + setup() { + const { page } = useData(); + onMounted(() => { + const LOCALE_STORAGE_KEY = 'cb-doc-locale'; + const path = window.location.pathname; + const locale = path.startsWith('/en/') ? '/en/' : path.startsWith('/de/') ? '/de/' : '/de/'; + // Persist the currently viewed locale so root can reuse the choice later + localStorage.setItem(LOCALE_STORAGE_KEY, locale); + // Keep zoom working across locales + mediumZoom('[data-zoomable]', { background: 'var(--vp-c-bg)' }); + }); + }, }; diff --git a/docs/de/documentation/advanced-functionality/cache.md b/docs/de/documentation/advanced-functionality/cache.md index 8e280ba5b..b1f37169d 100644 --- a/docs/de/documentation/advanced-functionality/cache.md +++ b/docs/de/documentation/advanced-functionality/cache.md @@ -36,7 +36,7 @@ Ein falsch konfigurierter Cache kann deine Seite verlangsamen. Probiere dann einen anderen Pfad für den Cache oder einen anderen Cache Adapter. * Falls deine Seite sehr langsam ist, kann das auch auf Problem mit dem Cache hindeuten. - Mehr dazu: [Die Seite ist sehr langsam](../faq/site-slow). + Mehr dazu: [Die Seite ist sehr langsam](../faq/index#my-site-is-very-slow-what-can-i-do). * Siehe auch die Seite [Häufige Fragen](../faq/) für bekannte Inkompatibilitäten. * **Regelmäßiges Aufwärmen des Caches durch Cronjob**: diff --git a/docs/de/documentation/advanced-functionality/hooks-and-filters.md b/docs/de/documentation/advanced-functionality/hooks-and-filters.md index 01f7587be..95acac837 100644 --- a/docs/de/documentation/advanced-functionality/hooks-and-filters.md +++ b/docs/de/documentation/advanced-functionality/hooks-and-filters.md @@ -85,7 +85,7 @@ zurückgibt. ### Alle Filter Hooks im Überblick: * commonsbooking_custom_metadata - * [commonsbooking_isCurrentUserAdmin](../basics/permission-management#filterhook-isCurrentUserAdmin) + * [commonsbooking_isUserAdmin](../basics/permission-management#filterhook-isUserAdmin) * commonsbooking_isCurrentUserSubscriber * commonsbooking_get_template_part * commonsbooking_template_tag @@ -96,6 +96,7 @@ zurückgibt. * commonsbooking_mail_body * commonsbooking_mail_attachment * commonsbooking_disableCache + * commonsbooking_gbfs_feeds Es gibt auch Filter Hooks, mit denen du zusätzliche Benutzerrollen, die zusätzlich zum CB Manager Artikel und Standorte administrieren können, diff --git a/docs/de/documentation/api/commonsbooking-api.md b/docs/de/documentation/api/commonsbooking-api.md index e42d0fe44..976fc7865 100644 --- a/docs/de/documentation/api/commonsbooking-api.md +++ b/docs/de/documentation/api/commonsbooking-api.md @@ -29,6 +29,10 @@ Die API erreichst du über _Einstellungen_ -> _CommonsBooking_ -> Tab: _API / Ex * Push-URL: Hier könnt ihr die URL des empfangenden Systems eingeben. CommonsBooking wird diese URL bei jeder Änderung der Daten aufrufen, sodass das entfernte System dann über eine Änderung der Daten informiert und diese über einen separaten API-Call abrufen kann. So kann ein Datenaustausch in Echtzeit ermöglicht werden. * API-Schlüssel: Hier könnt ihr einen selbstgewählten API-Schlüssel eingeben. Wenn der Schlüssel gesetzt ist, muss das abfragende System in jeder Abfrage den Parameter apikey= _[Schlüssel]_ mitliefern. +## Artikel von der API ausschliessen + +Wenn Artikel nicht in der API erscheinen sollen, müssen diese explizit ausgeschlossen werden. Diese Einstellungen kann auf Artikelebene vorgenommen werden, wenn dort der entsprechende Haken gesetzt ist, tauchen diese Artikel nicht in den API Routen auf. + ## Spezifikation der API-Routen **Verfügbarkeit** diff --git a/docs/de/documentation/api/gbfs.md b/docs/de/documentation/api/gbfs.md index aca58d32b..c8ea24219 100644 --- a/docs/de/documentation/api/gbfs.md +++ b/docs/de/documentation/api/gbfs.md @@ -1,17 +1,22 @@ # GBFS -::: danger Fehler in der API -Mit [Issue 1388](https://github.com/wielebenwir/commonsbooking/issues/1388) ist ein Fehler in der API dokumentiert. Die zeitliche Verfügbarkeit ist u.U. also nicht korrekt. -::: - -Seit 2.5 - Diese Schnittstelle stellt Daten der [Standorte](../first-steps/create-location), [Artikel](../first-steps/create-item) und deren Verfügbarkeit über die [Zeitrahmen](../first-steps/booking-timeframes-manage) in einem stadardisierten Schema bereit. -Die folgenden Endpunkte der _General Bikeshare Feed Specification_ ([GBFS](https://www.gbfs.org/documentation/)) Schema werden unterstützt: +Aktuell wird die Version 3.1-RC3 der _General Bikeshare Feed Specification_ ([GBFS](https://www.gbfs.org/documentation/)) unterstützt und die folgenden Endpunkte werden vom Plugin exponiert: + +* station_status.json +* station_information.json +* system_information.json +* vehicle_status.json +* vehicle_availability.json +* vehicle_types.json +* gbfs.json (Discovery) -* station_status -* station_information -* system_information -* gbfs.json (Discovery) \ No newline at end of file +## Zu vehicle_types.json + +Da über CommonsBooking hauptsächlich Lastenräder verliehen werden, gibt die API standardmäßig den `form_factor` als `cargo_bicycle` zurück. Da `propulsion_type` ein Pflichtfeld ist, wird hier standardmäßig `human` gesetzt. Wenn das nicht der Fall wäre, müssten noch viel mehr zusätzliche Informationen zum Antrieb zur Verfügung gestellt werden. + +::: info Behobenes Problem +Seit Juni 2026 (Version 2.11) ist der [Fehler zur Bereitstellung der zeitlichen Verfügbarkeit](https://github.com/wielebenwir/commonsbooking/issues/1388) behoben. +::: diff --git a/docs/de/documentation/basics/permission-management.md b/docs/de/documentation/basics/permission-management.md index af22ab9f6..7415c1fc2 100644 --- a/docs/de/documentation/basics/permission-management.md +++ b/docs/de/documentation/basics/permission-management.md @@ -60,14 +60,14 @@ Folgende Dinge darf der CommonsBooking Manager zum Beispiel nicht: * Das Design der Seite ändern * usw. -## CommonsBooking Manager zum Manager für alle Artikel / Standorte machen {#filterhook-isCurrentUserAdmin} +## CommonsBooking Manager zum Manager für alle Artikel / Standorte machen {#filterhook-isUserAdmin} Mithilfe eines [Filter Hooks](../advanced-functionality/hooks-and-filters) kannst du eine bestimmte Rolle so einstellen, dass sie automatisch Manager für alle Artikel / Standorte wird. Das unten genannte Beispiel macht das mit der Rolle 'cb_manager', also konfiguriert den CB-Manager so, dass er automatisch allen Artikeln und Standorten der Instanz zugerechnet wird. Falls das mit einer anderen Rolle passieren soll, muss diese Rolle auch den Manager Rollen mit einem [weiteren Codeschnipsel hinzugefügt werden](#filterhook-manager-roles). ```php add_filter( - 'commonsbooking_isCurrentUserAdmin', + 'commonsbooking_isUserAdmin', function ( bool $isAdmin, WP_User $user ) { return in_array( 'cb_manager', $user->roles, true ) ? true : $isAdmin; }, diff --git a/docs/de/documentation/faq/avoid-spam-registrations.md b/docs/de/documentation/faq/avoid-spam-registrations.md deleted file mode 100644 index 475a5f90f..000000000 --- a/docs/de/documentation/faq/avoid-spam-registrations.md +++ /dev/null @@ -1,9 +0,0 @@ -# Wie verhindere ich Spam Registrierungen - -Dafür gibt es verschiedene Möglichkeiten (Vorschläge aus der Community): - -* Ein HoneyPot lenkt Bots ab, ohne Menschen zu nerven: https://wordpress.org/plugins/honeypot/ - -* "Ich hatte mal für **UltimateMember ein winziges Plugin geschrieben mit dem man einfach einen Text eingeben muss um sich zu registrieren**. Barrierearm und hält alle Bots ab: [Download von Github](https://github.com/hansmorb/um-captchaquiz/raw/refs/heads/master/um-captchaquiz.zip). Dazu einfach eine Textbox erstellen und den Metaschlüssel in den Plugin Einstellungen eintragen." - -* "Wir nutzen Hcaptcha für wordpress. Nach der installation in den Einstellungen des Plugins die von euch genutzte Registrierung (z.B. UltraMember auswählen, standardmäßig sollte die WordPress-eigene Registrierung gewählt werden). Für die Nutzung muss ein Hcaptcha Account erstellt werden. Sie werben mit Privacy-First und das keine Nutzerdaten verkauft werden. Ich selber habe das nicht geprüft." — [Download aus dem Plugin-Verzeichnis](https://wordpress.org/plugins/hcaptcha-for-forms-and-more) diff --git a/docs/de/documentation/faq/booking-comment-emails.md b/docs/de/documentation/faq/booking-comment-emails.md deleted file mode 100644 index 6a80d0592..000000000 --- a/docs/de/documentation/faq/booking-comment-emails.md +++ /dev/null @@ -1,5 +0,0 @@ -# Wie bekomme ich den Buchungskommentar auf die Seite und in die Email? - -In den Einstellungen kannst du die Buchungskommentare aktivieren. In den email -Vorlagen musst du dann folgenden Code einfügen: `{{booking:returnComment}}` - diff --git a/docs/de/documentation/faq/index.md b/docs/de/documentation/faq/index.md index 973d42c8c..01cc4b9c5 100644 --- a/docs/de/documentation/faq/index.md +++ b/docs/de/documentation/faq/index.md @@ -1,105 +1,172 @@ -# Häufige Fragen (FAQ) +# Häufige Fragen (FAQ) {#faq} + -### Artikel +Diese Seite ist in zwei Bereiche unterteilt: [allgemeine **FAQ**](#faq) mit häufigen Fragen zur Nutzung, und [**Plugin- und Theme-Inkompatibilitäten**](#plugin-incompatibilities) mit bekannten Problemen durch Drittanbieter-Software. - * [ Wie bekomme ich den Buchungskommentar auf die Seite und in die Email? ](booking-comment-emails) - * [ Wie kann ich die Artikeldetailseite übersichtlicher gestalten? ](organise-article-page) - * [ Die Seite ist sehr langsam ](site-slow) - * [ Wie füge ich Zahlenschloss-Codes in E-Mails ein? ](lock-codes-email) + +## Wie bekomme ich den Buchungskommentar auf die Seite und in die Email? -## Ich möchte einzelne Nutzer vorübergehend sperren +::: details Antwort anzeigen +In den Einstellungen kannst du die Buchungskommentare aktivieren. In den E-Mail-Vorlagen musst du dann folgenden Code einfügen: `{{booking:returnComment}}` +::: + +## Wie kann ich die Artikeldetailseite übersichtlicher gestalten? + +::: details Antwort anzeigen +Lange Artikelseiten bedeuten, dass Menschen lange bis zum Buchungskalender scrollen müssen. + +Hier empfiehlt sich ein Plugin wie [Show-Hide/Collapse-Expand](https://de.wordpress.org/plugins/show-hidecollapse-expand) zu nutzen, mit dem Informationen eingeklappt werden können. + +![](/img/item-collapse.png) +::: + +## Meine Seite ist sehr langsam – was kann ich tun? {#my-site-is-very-slow-what-can-i-do} + +:::: details Antwort anzeigen +Wenn deine CommonsBooking Seite sehr langsam ist, kann das verschiedene Gründe haben. +Wir nutzen eine Technologie namens Caching, mit der wir häufig gestellte Anfragen in einem Zwischenspeicher +zurückhalten, um Serverkapazitäten einzusparen. + +Das Caching kann unter Umständen nicht funktionieren, wenn: + + * [WP_DEBUG](https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/) aktiviert ist, dafür musst du deine wp-config.php bearbeiten + * Der Ordner /tmp/ auf deinem Server nicht beschreibbar ist. Falls dies der Fall sein sollte, dann kontaktiere bitte deinen Webhoster und bitte ihn darum den Ordner beschreibbar zu machen. + * Falls das nicht möglich sein sollte, kannst du in den CommonsBooking Einstellungen unter "Erweiterte Optionen" den Pfad für den Dateisystem-Cache einstellen. Bitte frage bei deinem Webhoster nach, welche Ordner auf dem Server für temporäre Dateien verfügbar sind. + * Falls das auch nicht möglich sein sollte: Gehe zu deiner [Webseiten-Info](https://wordpress.org/documentation/article/site-health-screen/) unter (http://DEINE-URL/wp-admin/site-health.php?tab=debug). + Dort findest du unter **Verzeichnisse** den Pfad deines WordPress-Verzeichnisses. Wähle alternativ einen Ordner im Format `DEIN_VERZEICHNIS/symfony` als Cache-Ziel. + :::danger Achtung + Dies kann dazu führen, dass dein WordPress-Verzeichnis sehr groß wird. + ::: + +Alternativ kannst du auch [REDIS](https://redis.io) auf deinem Server installieren und den Cache durch REDIS verwalten lassen. +Da REDIS den Cache im RAM speichert, statt im Dateisystem, ist das meistens etwas schneller. +:::: -Ihr möchtet Nutzende vorübergehend für einen bestimmten Zeitraum sperren, weil diese z.B. die Ausleihe übermäßig nutzen oder gegen Ausleihbedingungen verstoßen? +## Wie kann ich Konfigurationsprobleme debuggen? -Ich würde euch dazu raten mit einem entsprechenden Plugin zum Blockieren von Nutzenden für einen bestimmten Zeitraum einfach den gesamten Login zu blockieren. Da gibt es auch schon einige Plugins dafür. Wenn eure Nutzenden sowieso nichts anderes auf der Seite machen können als Räder zu buchen erscheint mir das auch sinnvoll es auf diese Art und Weise zu machen. +:::: details Antwort anzeigen +:::warning Technische Expertise nötig! +::: + +Mit dem Plugin `query-monitor` kannst du Anfragen deiner Seite live überwachen. Damit ist es z.B. möglich einen +falsch konfigurierten Cache schnell zu identifizieren. +:::: + +## Wie füge ich Zahlenschloss-Codes in E-Mails ein? -Ich habe nur kurz bei mir mal das Plugin https://wordpress.org/plugins/user-blocker/ ausprobiert und das hat problemlos funktioniert, auch mit einer Zeitschaltfunktion. Das ist aber nicht das einzige Plugin, was diese Funktion hat. +::: details Antwort anzeigen +Eine häufige Frage ist, ob Codes für Zahlenschlösser an Artikeln oder Standorten hinzugefügt werden können, um sie in den versendeten E-Mails anzuzeigen. -Das Blockieren bestimmter Benutzergruppen ist kein Feature in CommonsBooking und wird wahrscheinlich auch so bald nicht als Feature kommen, da es schon einige Plugins gibt die genau das erledigen. +Das funktioniert über sog. Meta-Felder, welche Artikel und Standort zugewiesen werden. Diese Felder können dann auch in den E-Mail-Templates verwendet werden. -## Überbuchbare Tage erlauben / Buchung übers Wochenende +Der Artikel [Template-Tags](../administration/template-tags#eigene-metafelder-fur-standorte-und-artikel-verwenden) der Dokumentation enthält eine ausführliche Anleitung. +::: -Wenn ihr euren Nutzenden ermöglichen wollt, den Artikel z.B. über das Wochenende zu buchen, könnt ihr diese Einstellung in den Standort-Einstellungen vornehmen. +## Wie sperre ich einzelne Nutzer vorübergehend? -Infos dazu unter: https://commonsbooking.org/documentation/first-steps/create-location/ +::: details Antwort anzeigen +Möchtest du Nutzende vorübergehend für einen bestimmten Zeitraum sperren, weil diese z.B. die Ausleihe üdermäßig nutzen oder gegen Ausleihbedingungen verstoßen? -## Anzahl der Artikel in der cb_items Liste erhöhen +Wir empfehlen, ein dediziertes WordPress-Plugin zum Blockieren von Nutzenden zu verwenden. Wenn deine Nutzenden auf der Seite sowieso nichts anderes tun können als buchen, ist das auch die einfachste Lösung. -Die Anzahl der Artikel pro Seite wird über die globalen Einstellungen von Wordpress übernommen. +Das Plugin [User Blocker](https://wordpress.org/plugins/user-blocker/) wurde getestet und funktioniert problemlos, auch mit einer Zeitschaltfunktion. Es gibt weitere Plugins mit dieser Funktionalität. -Diese globale Einstellungen können hier geändert werden: +Das Blockieren bestimmter Benutzergruppen ist kein eingebautes Feature von CommonsBooking und wird wahrscheinlich auch in naher Zukunft nicht kommen, da es bereits WordPress-Plugins gibt, die genau das abdecken. +::: -Als Wordpress Administrator einlogge: +## Wie erlaube ich Buchungen über geschlossene Tage hinweg? -Einstellungen -> Lesen -> Blogseiten zeigen maximal +::: details Antwort anzeigen +Wenn du deinen Nutzenden ermöglichen möchtest, einen Artikel über geschlossene Tage hinweg zu buchen (z.B. über das Wochenende, wenn die Station geschlossen ist), kannst du das in den Standort-Einstellungen konfigurieren. -## Fehlerhafte Anzeige des Kalender-Widget im Admin-Bereich +Ausführliche Informationen findest du unter [Standorte anlegen](../first-steps/create-location). +::: + +## Wie erhöhe ich die Anzahl der Artikel in der cb_items-Liste? + +::: details Antwort anzeigen +Die Anzahl der Artikel pro Seite wird über die globalen WordPress-Leseeinstellungen übernommen. + +So änderst du sie: + +1. Als WordPress-Administrator einloggen +2. **Einstellungen -> Lesen** aufrufen +3. Den Wert bei **Blogseiten zeigen maximal** anpassen +::: -Treten Probleme bei der Anzeige des Kalenders im Admin-Bereich der Buchungen -auf (sog. Admin-Backend), siehe das folgende Bild rechts unten, kann eine -mögliche Lösung sein, das [ Plugin "Lightstart" (wp-maintenance-mode) ](https://wordpress.org/plugins/wp-maintenance-mode) zu deaktivieren oder zu -entfernen und neu zu installieren. Das Problem ist eine Inkompatibilität von -Lightstart mit CommonsBooking und kein Fehler im Code von CommonsBooking. Das -Problem tritt nicht mehr auf, wenn eine Neuinstallation von Lightstart -vorgenommen wurde. Mehr dazu auf [ Github im CommonsBooking Quellcode-Repository ](https://github.com/wielebenwir/commonsbooking/issues/1646). +## Wie verhindere ich Spam-Registrierungen? + +::: details Antwort anzeigen +Dafür gibt es verschiedene Möglichkeiten (Vorschläge aus der Community): + +* Ein HoneyPot lenkt Bots ab, ohne Menschen zu nerven: [Honeypot Plugin](https://wordpress.org/plugins/honeypot/) + +* "Ich hatte mal für **UltimateMember ein winziges Plugin geschrieben mit dem man einfach einen Text eingeben muss um sich zu registrieren**. Barrierearm und hält alle Bots ab: [Download von Github](https://github.com/hansmorb/um-captchaquiz/raw/refs/heads/master/um-captchaquiz.zip). Dazu einfach eine Textbox erstellen und den Metaschlüssel in den Plugin Einstellungen eintragen." + +* "Wir nutzen Hcaptcha für wordpress. Nach der Installation in den Einstellungen des Plugins die von euch genutzte Registrierung (z.B. UltimateMember) auswählen. Für die Nutzung muss ein Hcaptcha Account erstellt werden. Sie werben mit Privacy-First und das keine Nutzerdaten verkauft werden. Ich selber habe das nicht geprüft." - [Download aus dem Plugin-Verzeichnis](https://wordpress.org/plugins/hcaptcha-for-forms-and-more) +::: + +# Plugin- und Theme-Inkompatibilitäten {#plugin-incompatibilities} + +## Plugin: Lightstart + +::: details Antwort anzeigen +Treten Probleme bei der Anzeige des Kalenders im Admin-Bereich der Buchungen auf (sog. Admin-Backend), kann eine mögliche Lösung sein, das [Plugin "Lightstart" (wp-maintenance-mode)](https://wordpress.org/plugins/wp-maintenance-mode) zu deaktivieren oder zu entfernen und neu zu installieren. Das Problem ist eine Inkompatibilität von Lightstart mit CommonsBooking und kein Fehler im Code von CommonsBooking. Das Problem tritt nicht mehr auf, wenn eine Neuinstallation von Lightstart vorgenommen wurde. Mehr dazu auf [Github im CommonsBooking Quellcode-Repository](https://github.com/wielebenwir/commonsbooking/issues/1646). ![](/img/backend-booking-list-bug.png) +::: -## Inkompatibles Plugin All-in-one-Event Plugins +## Theme: GridBulletin + +::: details Antwort anzeigen +In der letzten Version von [GridBulletin](https://wordpress.org/themes/gridbulletin) kommt es zu einer Inkompatibilität mit CommonsBooking. Probleme tauchen auf, wenn der Footer aktiviert ist. Konkrete Probleme sind z.B. das Fehlen des Buchungs-Kalenders auf der Artikelseite. Aus technischer Sicht liegt es daran, dass die nötigen Javascript-Quellen von CommonsBooking nicht ausgeliefert werden. Der Grund innerhalb des GridBulletin Themes oder eine Lösung konnte bisher nicht gefunden werden. +::: +## Plugin: All-in-one-Event + +:::: details Antwort anzeigen :::info Behoben seit 2.7.2 (06.2022) Für Experten siehe [Issue 675](https://github.com/wielebenwir/commonsbooking/issues/675) ::: -Leider kommt es bei der gleichzeitigen Nutzung des Plugins "All-in-one-Event" zu Fehlern, sodass Seiten, die von CommonsBooking erzeugt werden nicht angezeigt werden. +Leider kommt es bei der gleichzeitigen Nutzung des Plugins "All-in-one-Event" zu Fehlern, sodass Seiten, die von CommonsBooking erzeugt werden, nicht angezeigt werden. Die Ursache ist leider auf eine schlechte Programmierung des All-in-one-Event-Plugins zurückzuführen, welches sich nicht an die Wordpress-Standards hält und so tief in Wordpress eingreift, dass es die Programmlogik von CommonsBooking quasi überschreibt. Wir haben einiges versucht, um eine parallele Nutzung zu ermöglichen, leider aber bisher keine Lösung gefunden. Wenn ihr das Problem auch habt, schreibt gerne direkt an den Support des Plugins, vielleicht passen sie ihr Plugin doch noch irgendwann an. +:::: -## Inkompatibles Plugin REDIS Object Cache - -Im Zusammenhang mit dem [Cache](../advanced-functionality/) gab -es in der Vergangenheit bereits Probleme mit anderen Wordpress-Plugins wie -z.B. 'REDIS Object Cache'. Aus diesem Grund raten wir von der Nutzung solcher -Plugins ab. +## Plugin: REDIS Object Cache -Deshalb sollten die von CommonsBooking generierten Seiten von der Optimierung durch Dritt-Plugins ausgenommen werden. -CommonsBooking verwendet ein eigenes Caching. +::: details Antwort anzeigen +Im Zusammenhang mit dem [Cache](../advanced-functionality/) gab es in der Vergangenheit bereits Probleme mit anderen Wordpress-Plugins wie z.B. 'REDIS Object Cache'. Aus diesem Grund raten wir von der Nutzung solcher Plugins ab. +Die von CommonsBooking generierten Seiten sollten von der Optimierung durch Dritt-Plugins ausgenommen werden. CommonsBooking verwendet ein eigenes Caching. +::: -## Inkompatibles Plugin Ultimate Member +## Plugin: Ultimate Member -Wenn ihr das Plugin Ultimate Member benutzt und die Benutzerrolle "CommonsBooking Manager" nutzen möchtet, müsst ihr in Ultimate Member für die Rolle cb_manager noch ein Häkchen setzen, um diese für den AP-Admin-Zugang zu aktivieren. +::: details Antwort anzeigen +Wenn ihr das Plugin Ultimate Member benutzt und die Benutzerrolle "CommonsBooking Manager" nutzen möchtet, müsst ihr in Ultimate Member für die Rolle `cb_manager` noch ein Häkchen setzen, um diese für den Admin-Zugang zu aktivieren. +::: -## Inkompatible Plugins: Autoptimize / Caching +## Plugin: Autoptimize / Caching-Plugins -Optimierungs-Plugins oder weitere Caching-Plugins können dazu führen, dass CommonsBooking nicht alle Seiten anzeigen kann. +:::: details Antwort anzeigen +Optimierungs-Plugins oder weitere Caching-Plugins können dazu führen, dass CommonsBooking nicht alle Seiten korrekt anzeigen kann. -Nicht vollständige Liste: +Betroffene Plugins (nicht vollständig): * Autoptimize -Deshalb sollten die von CommonsBooking generierten Seiten von der Optimierung durch Dritt-Plugins ausgenommen werden. -CommonsBooking verwendet ein eigenes Caching. +Die von CommonsBooking generierten Seiten sollten von der Optimierung durch Dritt-Plugins ausgenommen werden. CommonsBooking verwendet ein eigenes Caching. -::: info Hast du ein Problem festgestellt? +:::info Hast du ein Problem festgestellt? Dann trage die Inkompatibilität hier ein! ::: - - -## Inkompatibles Theme Gridbulletin - -In der letzten Version von [ GridBulletin ](https://wordpress.org/themes/gridbulletin) kommt es zu einer -Inkompatibilität mit CommonsBooking. Probleme tauchen auf, wenn der Footer -aktiviert ist. Konkrete Probleme sind z.B. das Fehlen des Buchungs-Kalenders -auf der Artikelseite. Aus technischer Sicht liegt es daran, dass die nötigen -Javascript-Quellen von CommonsBooking nicht ausgeliefert werden. Der Grund -innerhalb des GridBulletin Themes oder eine Lösung konnte bisher nicht -gefunden werden. - - - +:::: diff --git a/docs/de/documentation/faq/lock-codes-email.md b/docs/de/documentation/faq/lock-codes-email.md deleted file mode 100644 index 1d000040d..000000000 --- a/docs/de/documentation/faq/lock-codes-email.md +++ /dev/null @@ -1,11 +0,0 @@ -# Wie füge ich Zahlenschloss-Codes in E-Mails ein? - -Eine häufige Frage ist, ob Codes für Zahlenschlösser an Artikeln oder -Standorten hinzugefügt werden können um Sie in den versendeten E-Mails -anzuzeigen. - -Das funktioniert über sog. Meta-Felder, welche Artikel und Standort zugewiesen -werden. Diese Felder können dann auch in den E-Mail Templates verwendet -werden. - -Der Aritkel [Template-Tags](../administration/template-tags#eigene-metafelder-fur-standorte-und-artikel-verwenden) der Dokumentation enthält eine Ausführliche Anleitung. diff --git a/docs/de/documentation/faq/organise-article-page.md b/docs/de/documentation/faq/organise-article-page.md deleted file mode 100644 index cbce05f12..000000000 --- a/docs/de/documentation/faq/organise-article-page.md +++ /dev/null @@ -1,13 +0,0 @@ -# Wie kann ich die Artikeldetailseite übersichtlicher gestalten? - -## Informationen erst auf Klick anzeigen - -Lange Artikelseiten bedeuten, dass Menschen lange bis zum Buchungskalender -scrollen müssen. - -Hier empfiehlt sich ein Plugin wie [ Show-Hide/Collapse-Expand -](https://de.wordpress.org/plugins/show-hidecollapse-expand) zu nutzen, mit -dem Informationen eingeklappt werden können. - -![](/img/item-collapse.png) - diff --git a/docs/de/documentation/faq/problems-and-answers.md b/docs/de/documentation/faq/problems-and-answers.md deleted file mode 100644 index aebab7705..000000000 --- a/docs/de/documentation/faq/problems-and-answers.md +++ /dev/null @@ -1,27 +0,0 @@ -# Probleme und Antworten - -### Anzeige Kalender-Widget im Admin-Bereich - -Treten Probleme bei der Anzeige des Kalenders im Admin-Bereich der Buchungen -auf (sog. Admin-Backend), siehe das folgende Bild rechts unten, kann eine -mögliche Lösung sein, das [ Plugin "Lightstart" (wp-maintenance-mode) -](https://wordpress.org/plugins/wp-maintenance-mode) zu deaktivieren oder zu -entfernen und neu zu installieren. Das Problem ist eine Inkompatibilität von -Lightstart mit CommonsBooking und kein Fehler im Code von CommonsBooking. Das -Problem tritt nicht mehr auf, wenn eine Neuinstallation von Lightstart -vorgenommen wurde. Mehr dazu auf [ Github im CommonsBooking Quellcode- -Repository ](https://github.com/wielebenwir/commonsbooking/issues/1646) . - -![](/img/backend-booking-list-bug.png) - -### Inkompatibles Theme Gridbulletin - -In der letzten Version von [ GridBulletin -](https://wordpress.org/themes/gridbulletin) kommt es zu einer -Inkompatibilität mit CommonsBooking. Probleme tauchen auf, wenn der Footer -aktiviert ist. Konkrete Probleme sind z.B. das Fehlen des Buchungs-Kalenders -auf der Artikelseite. Aus technischer Sicht liegt es daran, dass die nötigen -Javascript-Quellen von CommonsBooking nicht ausgeliefert werden. Der Grund -innerhalb des GridBulletin Themes oder eine Lösung konnte bisher nicht -gefunden werden. - diff --git a/docs/de/documentation/faq/site-slow.md b/docs/de/documentation/faq/site-slow.md deleted file mode 100644 index 582b2f284..000000000 --- a/docs/de/documentation/faq/site-slow.md +++ /dev/null @@ -1,28 +0,0 @@ -# Die Seite ist sehr langsam - -Wenn deine CommonsBooking Seite sehr langsam ist, kann das verschiedene Gründe haben. -Wir nutzen eine Technologie namens Caching, mit der wir häufig gestellte Anfragen in einem Zwischenspeicher -zurückhalten, um Serverkapazitäten einzusparen. - -Das Caching kann unter Umständen nicht funktionieren, wenn: - - * [WP_DEBUG](https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/) aktiviert ist, dafür musst du deine wp-config.php bearbeiten - * Der Ordner /tmp/ auf deinem Server nicht beschreibbar ist. Falls dies der Fall sein sollte, dann kontaktiere bitte deinen Webhoster und bitte ihn darum den Ordner beschreibbar zu machen. - * Falls das nicht möglich sein sollte, kannst du in den CommonsBooking Einstellungen unter “Erweiterte Optionen” den Pfad für den Dateisystem-Cache einstellen. Bitte frage bei deinem Webhoster nach, welche Ordner auf dem Server für temporäre Dateien verfügbar sind. - * Falls das auch nicht möglich sein sollte: Gehe zu deiner [Webseiten-Info](https://wordpress.org/documentation/article/site-health-screen/) unter (http://DEINE-URL/wp-admin/site-health.php?tab=debug). - Dort findest du unter **Verzeichnisse** den Pfad deines WordPress-Verzeichnisses. Wähle alternativ einen Ordner im Format `DEIN_VERZEICHNIS/symfony` als Cache-Ziel. - ::: danger Achtung - Dies kann dazu führen, dass dein WordPress-Verzeichnis sehr groß wird. - ::: - -Alternativ kannst du auch [REDIS](https://redis.io) auf deinem Server installieren und den Cache durch REDIS verwalten lassen. -Da REDIS den Cache im RAM speichert, statt im Dateisystem, ist das meistens etwas schneller. - -## Troubleshooting - -::: warning Technische Expertise nötig! -::: - -Mit dem Plugin `query-monitor` kannst du Anfragen deiner Seite live überwachen. Damit es es z.B. möglich ein -falsch konfigurierten Cache schnell zu identifizieren. - diff --git a/docs/de/documentation/first-steps/create-item.md b/docs/de/documentation/first-steps/create-item.md index 1697a2426..8385c43a3 100644 --- a/docs/de/documentation/first-steps/create-item.md +++ b/docs/de/documentation/first-steps/create-item.md @@ -1,6 +1,11 @@ # Artikel anlegen +:::tip Wofür nutze ich Kategorien? +Dieser WordPress Post-Typ kann mit einer [Kategorie](https://wordpress.org/documentation/article/posts-categories-screen/) konfiguriert werden. +Innerhalb von CommonsBooking kannst du Kategorien eines Artikels in den [Shortcodes](../administration/shortcodes) verwenden. +::: + **Beschreibung des Artikels** Nutze den großen Texteditor oben auf der Artikelseite nur für die @@ -29,3 +34,4 @@ Ergänze hier die Kurzversion der Artikelbeschreibung, diese wird in der Artikel Es ist möglich einen Artikel mit einem Passwort zu versehen. Klicke dafür neben "Status" auf der rechten Seite des Artikels und füge ein Passwort hinzu. Jetzt können Nutzende diesen Artikel nur buchen, wenn das korrekte Passwort eingegeben wurde. ![](/img/item-password.png){width="400"} + diff --git a/docs/de/documentation/first-steps/create-location.md b/docs/de/documentation/first-steps/create-location.md index 73a2672e7..6caf2e2ef 100644 --- a/docs/de/documentation/first-steps/create-location.md +++ b/docs/de/documentation/first-steps/create-location.md @@ -1,5 +1,9 @@ # Station anlegen +:::tip Wofür nutze ich Kategorien? +Dieser WordPress Post-Typ kann mit einer [Kategorie](https://wordpress.org/documentation/article/posts-categories-screen/) konfiguriert werden. +Innerhalb von CommonsBooking kannst du Kategorien einer Station in den [Shortcodes](../administration/shortcodes) verwenden. +::: ## Stationsbeschreibung @@ -88,3 +92,4 @@ würde_ ) ![](/img/overbooking-countone.png){data-zoomable} _Nur der erste Tag wird bei der Überbuchung gezählt: Das Wochenende ist somit überbuchbar aber es kann nicht bis Dienstag gebucht werden._ + diff --git a/docs/de/documentation/setup/migration-from-cb1.md b/docs/de/documentation/setup/migration-from-cb1.md index b35fc55b9..6610466cc 100644 --- a/docs/de/documentation/setup/migration-from-cb1.md +++ b/docs/de/documentation/setup/migration-from-cb1.md @@ -1,5 +1,9 @@ # Migration von Version 0.9.x +:::danger ACHTUNG +Mit CommonsBooking 2.12 (Veröffentlichung Anfang 2027) wird die Migration von CommonsBooking 0.9.X auf die neuste Version eingestellt. +Alle Nutzenden von CommonsBooking 0.9.X sind dazu angehalten **zeitnah zu migrieren**, bei Fragen unterstützen wir gerne und helfen euch auch gerne bei der Migration. +::: Die Migration von Version CB 0.9.x zu CB 2.x.x könnt ihr per Knopfdruck erledigen. Die Migration importiert folgende Daten: diff --git a/docs/en/documentation/advanced-functionality/cache.md b/docs/en/documentation/advanced-functionality/cache.md index 03fa863d0..a6dc8563d 100644 --- a/docs/en/documentation/advanced-functionality/cache.md +++ b/docs/en/documentation/advanced-functionality/cache.md @@ -36,7 +36,7 @@ A misconfigured cache can slow down your site! working properly. In that case, try a different path for the cache or a different cache adapter. * If your site is very slow, this may also indicate a problem with the cache. - More about this: [The site is very slow](../faq/site-slow). + More about this: [The site is very slow](../faq/index#my-site-is-very-slow-what-can-i-do). * **Periodical cache warmup through cron job**: :::warning diff --git a/docs/en/documentation/advanced-functionality/hooks-and-filters.md b/docs/en/documentation/advanced-functionality/hooks-and-filters.md index fa83c1623..e5be8431a 100644 --- a/docs/en/documentation/advanced-functionality/hooks-and-filters.md +++ b/docs/en/documentation/advanced-functionality/hooks-and-filters.md @@ -77,7 +77,7 @@ receives a value, modifies it, and then returns it. ### Overview of all filter hooks * commonsbooking_custom_metadata - * [commonsbooking_isCurrentUserAdmin](../basics/permission-management#filterhook-isCurrentUserAdmin) + * [commonsbooking_isUserAdmin](../basics/permission-management#filterhook-isUserAdmin) * commonsbooking_isCurrentUserSubscriber * commonsbooking_get_template_part * commonsbooking_template_tag @@ -88,6 +88,7 @@ receives a value, modifies it, and then returns it. * commonsbooking_mail_body * commonsbooking_mail_attachment * commonsbooking_disableCache + * commonsbooking_gbfs_feeds There are also filter hooks that allow you to add additional user roles akin to the CB Manager that can manage items and locations. diff --git a/docs/en/documentation/api/commonsbooking-api.md b/docs/en/documentation/api/commonsbooking-api.md index 5eb756105..51420d144 100644 --- a/docs/en/documentation/api/commonsbooking-api.md +++ b/docs/en/documentation/api/commonsbooking-api.md @@ -26,6 +26,10 @@ You can access the API via _Settings_ -> _CommonsBooking_ -> Tab: _API / Export_ * Push URL: Here you can enter the URL of the receiving system. CommonsBooking will call this URL whenever the data changes, so that the remote system is informed about a data change and can retrieve it via a separate API call. This enables real-time data exchange. * API Key: Here you can enter a custom API key. If the key is set, the requesting system must provide the parameter apikey= _[key]_ in every query. +## Excluding items from the API + +If you do not want certain items to appear in the API, they must be explicitly excluded. These settings can be configured at item level; if the relevant checkbox is ticked, these items will not appear in the API routes. + ## API route specification **Availability** diff --git a/docs/en/documentation/api/gbfs.md b/docs/en/documentation/api/gbfs.md index e34ae5aea..22ce62af2 100644 --- a/docs/en/documentation/api/gbfs.md +++ b/docs/en/documentation/api/gbfs.md @@ -1,17 +1,21 @@ # GBFS -::: danger API bug -A bug in the API is documented in [Issue 1388](https://github.com/wielebenwir/commonsbooking/issues/1388). The temporal availability may therefore not be correct. -::: - -Since 2.5 - This interface provides data of [locations](../first-steps/create-location), [items](../first-steps/create-item) and their availability via [timeframes](../first-steps/booking-timeframes-manage) in a standardized schema. -The following endpoints of the _General Bikeshare Feed Specification_ ([GBFS](https://www.gbfs.org/documentation/)) schema are supported: +Currently, version 3.1-RC3 of the _General Bikeshare Feed Specification_ ([GBFS](https://www.gbfs.org/documentation/)) is supported with the following routes: -* station_status -* station_information -* system_information +* station_status.json +* station_information.json +* system_information.json +* vehicle_status.json +* vehicle_availability.json +* vehicle_types.json * gbfs.json (Discovery) + +## Regarding vehicle_types.json + +Since CommonsBooking is primarily used to rent out cargo bikes, the API returns `cargo_bicycle` as the default value for `form_factor`. As `propulsion_type` is a required field, the default value here is set to `human`. If this were not the case, much more additional information about the propulsion method would need to be provided. + +::: info Fixed Issue +Since June 2026 (version 2.11) the [issue regarding a wrong display of availability](https://github.com/wielebenwir/commonsbooking/issues/1388) is fixed. diff --git a/docs/en/documentation/basics/permission-management.md b/docs/en/documentation/basics/permission-management.md index b45b586d8..888a95ad5 100644 --- a/docs/en/documentation/basics/permission-management.md +++ b/docs/en/documentation/basics/permission-management.md @@ -47,7 +47,7 @@ In addition, CommonsBooking Managers have no special permissions regarding other * Change the site design * etc. -## Make a CommonsBooking Manager a manager for all items / locations {#filterhook-isCurrentUserAdmin} +## Make a CommonsBooking Manager a manager for all items / locations {#filterhook-isUserAdmin} With a [filter hook](../advanced-functionality/hooks-and-filters) you can set a specific role so that it automatically becomes a manager for all items / locations. The example below does this for the role 'cb_manager', i.e. it configures the CB Manager to be automatically assigned to all items and locations in the instance. @@ -55,7 +55,7 @@ If this should happen with a different role, that role must also be added to the ```php add_filter( - 'commonsbooking_isCurrentUserAdmin', + 'commonsbooking_isUserAdmin', function ( bool $isAdmin, WP_User $user ) { return in_array( 'cb_manager', $user->roles, true ) ? true : $isAdmin; }, diff --git a/docs/en/documentation/faq/avoid-spam-registrations.md b/docs/en/documentation/faq/avoid-spam-registrations.md deleted file mode 100644 index 8c0efe268..000000000 --- a/docs/en/documentation/faq/avoid-spam-registrations.md +++ /dev/null @@ -1,9 +0,0 @@ -# How do I prevent spam registrations - -There are several ways to do this (suggestions from the community): - -* A honeypot diverts bots without bothering people: https://wordpress.org/plugins/honeypot/ - -* "I once wrote a tiny plugin for **UltimateMember where you simply have to enter a text to register**. Accessible and it keeps all bots out: [Download from GitHub](https://github.com/hansmorb/um-captchaquiz/raw/refs/heads/master/um-captchaquiz.zip). Just create a text box and enter the meta key in the plugin settings." - -* "We use hCaptcha for WordPress. After installation, select the registration you use in the plugin settings (e.g., UltimateMember; by default the built-in WordPress registration should be selected). To use it, you need to create an hCaptcha account. They advertise Privacy-First and that no user data is sold. I have not checked this myself." — [Download from the plugin directory](https://wordpress.org/plugins/hcaptcha-for-forms-and-more) diff --git a/docs/en/documentation/faq/booking-comment-emails.md b/docs/en/documentation/faq/booking-comment-emails.md deleted file mode 100644 index 4598c49f1..000000000 --- a/docs/en/documentation/faq/booking-comment-emails.md +++ /dev/null @@ -1,3 +0,0 @@ -# How do I show the booking comment on the page and in the email? - -In the settings you can enable booking comments. In the email templates you then need to insert the following code:
`{{booking:returnComment}}`
diff --git a/docs/en/documentation/faq/index.md b/docs/en/documentation/faq/index.md index 958700318..04d4f5557 100644 --- a/docs/en/documentation/faq/index.md +++ b/docs/en/documentation/faq/index.md @@ -1,46 +1,121 @@ -# Frequently Asked Questions (FAQ) +# Frequently Asked Questions (FAQ) {#faq} -### Pages + - * [How do I show the booking comment on the page and in the email?](booking-comment-emails) - * [How can I make the item detail page clearer?](organise-article-page) - * [The site is very slow](site-slow) - * [How do I show lock codes in emails?](lock-codes-email) +This page is split into two sections: [general **FAQ**](#faq) with common how-to questions, and [**Plugin & Theme Incompatibilities**](#plugin-incompatibilities) listing known issues with third-party software. -## I want to temporarily block individual users + +## How do I show the booking comment on the page and in the email? + +::: details Expand for answer +In the settings you can enable booking comments. In the email templates you then need to insert the following code:
`{{booking:returnComment}}`
+::: + +## How can I make the item detail page clearer? + +::: details Expand for answer +Long item pages mean users have to scroll a long way to reach the booking calendar. + +A plugin such as [Show-Hide/Collapse-Expand](https://de.wordpress.org/plugins/show-hidecollapse-expand) can be used to collapse information. + +![](/img/item-collapse.png) +::: + +## My site is very slow, what can I do? + +::: details Expand for answer +If your CommonsBooking site is very slow, there may be several underlying causes. +We use a technology called caching, which keeps frequently requested data +in temporary storage to save server resources. +Caching may not work under certain conditions, for example when: + + * [WP_DEBUG](https://wordpress.org/documentation/article/debugging-in-wordpress) is enabled; in that case you need to edit your wp-config.php + * The /tmp/ folder on your server is not writable. If that is the case, contact your web host and ask them to make the folder writable. + * If that is not possible, you can set the path for the filesystem cache in the CommonsBooking settings under "Advanced Options". Ask your web host which folders on the server are available for temporary files. + * If that is also not possible: Go to your Site Health screen at (http://YOUR-URL/wp-admin/site-health.php?tab=debug). There you will find the path to your WordPress directory under **Directories**. Alternatively, choose a folder in the format `YOUR_DIRECTORY/symfony` as the cache target. **Warning:** This can cause your WordPress directory to grow very large. + +Alternatively, you can install [Redis](https://redis.io) on your server and let Redis manage the cache. Since Redis stores the cache in RAM instead of the filesystem, it is usually a bit faster. +::: + +## How do I show lock codes in emails? + +::: details Expand for answer +A frequent question is whether lock codes for combination locks can be added to items or locations so that they are displayed in the sent emails. + +This is possible via so-called meta fields, which are assigned to items and locations. These fields can then also be used in email templates. + +[This page of the documentation contains a detailed guide.](../administration/template-tags) +::: + +## How do I temporarily block individual users? + +::: details Expand for answer Do you want to temporarily block users for a certain period of time, e.g. because they use the rental service excessively or violate the rental conditions? -I would advise you to simply block the entire login with an appropriate plugin for blocking users for a certain period of time. There are already some plugins for this. If your users can't do anything else on the site anyway other than booking bikes, it seems to make sense to do it this way. +The recommended approach is to use a dedicated WordPress plugin for blocking users. If your users cannot do anything on the site other than making bookings, this is also the simplest solution. -I just briefly tried the plugin https://wordpress.org/plugins/user-blocker/ and it worked without any problems, even with a timer function. But this is not the only plugin that has this function. +The plugin [User Blocker](https://wordpress.org/plugins/user-blocker/) has been tested and works without issues, including a timer function. There are other plugins available with the same functionality. -Blocking specific user groups is not a feature in CommonsBooking and probably won't be added as a feature anytime soon, as there are already some plugins that do exactly that. +Blocking specific user groups is not a built-in feature of CommonsBooking and is unlikely to be added soon, as existing WordPress plugins already cover this use case well. +::: -## Allow overbookable days / booking over the weekend +## How do I allow booking across closed days? -If you want to allow your users to book the item over the weekend, for example, you can make this setting in the location settings. +::: details Expand for answer +If you want to allow your users to book an item across closed days (e.g. over a weekend when the station is closed), you can configure this in the location settings. -More information at: https://commonsbooking.org/documentation/first-steps/create-location/ +For detailed instructions, see [Create Locations](../first-steps/create-location). +::: -## Increase the number of items in the cb_items list +## How do I increase the number of items shown in the cb_items list? -The number of items per page is taken from the global WordPress settings. +::: details Expand for answer +The number of items shown per page is taken from the global WordPress reading settings. -These global settings can be changed here: +To change it: -Log in as WordPress administrator: +1. Log in as a WordPress administrator +2. Go to **Settings -> Reading** +3. Change the value for **Blog pages show at most** +::: -Settings -> Reading -> Blog pages show at most +## How do I prevent spam registrations? -## Incorrect display of the calendar widget in the admin area +::: details Expand for answer +There are several ways to do this (suggestions from the community): + +* A honeypot diverts bots without bothering people: [Honeypot plugin](https://wordpress.org/plugins/honeypot/) + +* "I once wrote a tiny plugin for **UltimateMember where you simply have to enter a text to register**. Accessible and it keeps all bots out: [Download from GitHub](https://github.com/hansmorb/um-captchaquiz/raw/refs/heads/master/um-captchaquiz.zip). Just create a text box and enter the meta key in the plugin settings." + +* "We use hCaptcha for WordPress. After installation, select the registration you use in the plugin settings (e.g., UltimateMember; by default the built-in WordPress registration should be selected). To use it, you need to create an hCaptcha account. They advertise Privacy-First and that no user data is sold. I have not checked this myself." - [Download from the plugin directory](https://wordpress.org/plugins/hcaptcha-for-forms-and-more) +::: -If there are problems displaying the calendar in the admin area of the bookings (so-called admin backend), see the following picture on the bottom right, a possible solution can be to deactivate or remove and reinstall the [ "Lightstart" (wp-maintenance-mode) plugin ](https://wordpress.org/plugins/wp-maintenance-mode). The problem is an incompatibility of Lightstart with CommonsBooking and not an error in the CommonsBooking code. The problem no longer occurs if Lightstart has been reinstalled. Read more about this on [ Github in the CommonsBooking source code repository ](https://github.com/wielebenwir/commonsbooking/issues/1646). +# Plugin & Theme Incompatibilities {#plugin-incompatibilities} + +## Plugin: Lightstart + +::: details Expand for answer +If there are problems displaying the calendar in the booking admin area (the admin backend), see the image below on the right, one possible solution is to disable or remove and reinstall the ["Lightstart" (wp-maintenance-mode) plugin](https://wordpress.org/plugins/wp-maintenance-mode). +The issue is an incompatibility between Lightstart and CommonsBooking and not a bug in CommonsBooking's code. +The problem does not occur after reinstalling Lightstart. More details on [GitHub in the CommonsBooking source repository](https://github.com/wielebenwir/commonsbooking/issues/1646). ![](/img/backend-booking-list-bug.png) +::: + +## Theme: GridBulletin -## Incompatible plugin All-in-one-Event Plugins +::: details Expand for answer +The latest version of [GridBulletin](https://wordpress.org/themes/gridbulletin) is incompatible with CommonsBooking. +Problems occur when the footer is enabled. One concrete issue is the missing booking calendar on the item page. From a technical perspective, the required JavaScript sources from CommonsBooking are not being loaded. The root cause within the GridBulletin theme or a solution has not yet been found. +::: + +## Plugin: All-in-one-Event +:::: details Expand for answer :::info Fixed since 2.7.2 (06.2022) For experts see [Issue 675](https://github.com/wielebenwir/commonsbooking/issues/675) ::: @@ -52,28 +127,35 @@ The cause is unfortunately due to poor programming of the All-in-one-Event plugi We have tried a few things to enable parallel use, but unfortunately have not found a solution yet. If you also have the problem, please write directly to the plugin's support, maybe they will adapt their plugin at some point. +:::: -## Incompatible plugin REDIS Object Cache +## Plugin: REDIS Object Cache +::: details Expand for answer In connection with the [Cache](../advanced-functionality/), there have been problems with other WordPress plugins such as 'REDIS Object Cache' in the past. For this reason, we advise against using such plugins. -Therefore, the pages generated by CommonsBooking should be excluded from optimization by third-party plugins. +The pages generated by CommonsBooking should be excluded from optimization by third-party plugins. CommonsBooking uses its own caching. +::: -## Incompatible plugin Ultimate Member +## Plugin: Ultimate Member -If you use the Ultimate Member plugin and want to use the "CommonsBooking Manager" user role, you have to check a box in Ultimate Member for the cb_manager role to activate it for AP admin access. +::: details Expand for answer +If you use the Ultimate Member plugin and want to use the "CommonsBooking Manager" user role, you have to check a box in Ultimate Member for the `cb_manager` role to activate it for admin access. +::: -## Incompatible plugins: Autoptimize / Caching +## Plugin: Autoptimize / Caching plugins -Optimization plugins or other caching plugins can cause CommonsBooking to not be able to display all pages. +:::: details Expand for answer +Optimization plugins or other caching plugins can cause CommonsBooking to not display all pages correctly. -Incomplete list: +Affected plugins include (incomplete list): * Autoptimize -Therefore, the pages generated by CommonsBooking should be excluded from optimization by third-party plugins. +The pages generated by CommonsBooking should be excluded from optimization by third-party plugins. CommonsBooking uses its own caching. -::: info Have you noticed a problem? -Then enter the incompatibility here! +:::info Have you noticed a problem? +Add incompatible plugins or themes here! ::: +:::: diff --git a/docs/en/documentation/faq/lock-codes-email.md b/docs/en/documentation/faq/lock-codes-email.md deleted file mode 100644 index c3ddad0b3..000000000 --- a/docs/en/documentation/faq/lock-codes-email.md +++ /dev/null @@ -1,8 +0,0 @@ -# How do I show lock codes in emails? - -A frequent question is whether lock codes for combination locks can be added to items or locations so that they are displayed in the sent emails. - -This is possible via so-called meta fields, which are assigned to items and locations. These fields can then also be used in email templates. -werden. - -[This page of the documentation contains a detailed guide.](../administration/template-tags) diff --git a/docs/en/documentation/faq/organise-article-page.md b/docs/en/documentation/faq/organise-article-page.md deleted file mode 100644 index a5794ecca..000000000 --- a/docs/en/documentation/faq/organise-article-page.md +++ /dev/null @@ -1,9 +0,0 @@ -# How can I make the item detail page clearer? - -## Information only shown on click - -Long item pages mean users have to scroll a long way to reach the booking calendar. - -A plugin such as [Show-Hide/Collapse-Expand](https://de.wordpress.org/plugins/show-hidecollapse-expand) can be used to collapse information. - -![](/img/item-collapse.png) diff --git a/docs/en/documentation/faq/problems-and-answers.md b/docs/en/documentation/faq/problems-and-answers.md deleted file mode 100644 index 3a8582ec6..000000000 --- a/docs/en/documentation/faq/problems-and-answers.md +++ /dev/null @@ -1,14 +0,0 @@ -# Problems and answers - -### Calendar widget display in the admin area - -If there are problems displaying the calendar in the booking admin area (the admin backend), see the image below on the right, one possible solution is to disable or remove and reinstall the ["Lightstart" (wp-maintenance-mode) plugin](https://wordpress.org/plugins/wp-maintenance-mode). -The issue is an incompatibility between Lightstart and CommonsBooking and not a bug in CommonsBooking's code. -The problem does not occur after reinstalling Lightstart. More details on [GitHub in the CommonsBooking source repository](https://github.com/wielebenwir/commonsbooking/issues/1646). - -![](/img/backend-booking-list-bug.png) - -### Incompatible theme: GridBulletin - -The latest version of [GridBulletin](https://wordpress.org/themes/gridbulletin) is incompatible with CommonsBooking. -Problems occur when the footer is enabled. One concrete issue is the missing booking calendar on the item page. From a technical perspective, the required JavaScript sources from CommonsBooking are not being loaded. The root cause within the GridBulletin theme or a solution has not yet been found. diff --git a/docs/en/documentation/faq/site-slow.md b/docs/en/documentation/faq/site-slow.md deleted file mode 100644 index a2c19002b..000000000 --- a/docs/en/documentation/faq/site-slow.md +++ /dev/null @@ -1,13 +0,0 @@ -# The site is very slow - -If your CommonsBooking site is very slow, there may be several underlying causes. -We use a technology called caching, which keeps frequently requested data -in temporary storage to save server resources. -Caching may not work under certain conditions, for example when: - - * [WP_DEBUG](https://wordpress.org/documentation/article/debugging-in-wordpress) is enabled; in that case you need to edit your wp-config.php - * The /tmp/ folder on your server is not writable. If that is the case, contact your web host and ask them to make the folder writable. - * If that is not possible, you can set the path for the filesystem cache in the CommonsBooking settings under "Advanced Options". Ask your web host which folders on the server are available for temporary files. - * If that is also not possible: Go to your Site Health screen at (http://YOUR-URL/wp-admin/site-health.php?tab=debug). There you will find the path to your WordPress directory under **Directories**. Alternatively, choose a folder in the format `YOUR_DIRECTORY/symfony` as the cache target. **Warning:** This can cause your WordPress directory to grow very large. - -Alternatively, you can install [Redis](https://redis.io) on your server and let Redis manage the cache. Since Redis stores the cache in RAM instead of the filesystem, it is usually a bit faster. diff --git a/docs/en/documentation/setup/migration-from-cb1.md b/docs/en/documentation/setup/migration-from-cb1.md index 89a92dba3..04c390412 100644 --- a/docs/en/documentation/setup/migration-from-cb1.md +++ b/docs/en/documentation/setup/migration-from-cb1.md @@ -1,5 +1,10 @@ # Migration from version 0.9.x +:::danger danger +With CommonsBooking 2.12 (releasing early 2027), migration support from CommonsBooking 0.9.X to the latest version will end. +All users of CommonsBooking 0.9.X are urged to **migrate as soon as possible**. We are happy to help with any questions and will support you in migration. +::: + You can migrate from CB 0.9.x to CB 2.x.x with a single click. The migration imports the following data: * Items diff --git a/includes/OptionsArray.php b/includes/OptionsArray.php index 0601828bc..75a9a814b 100644 --- a/includes/OptionsArray.php +++ b/includes/OptionsArray.php @@ -1451,6 +1451,18 @@ 'id' => 'apikey_not_required', 'type' => 'checkbox', ), + array( + 'name' => esc_html__( 'Disable Commons API', 'commonsbooking' ), + 'desc' => commonsbooking_sanitizeHTML( __( 'If selected, the Commons API endpoints (availability, items, locations, projects) are not registered, while the rest of the API stays active.', 'commonsbooking' ) ), + 'id' => 'commons-api-disabled', + 'type' => 'checkbox', + ), + array( + 'name' => esc_html__( 'Disable GBFS API', 'commonsbooking' ), + 'desc' => commonsbooking_sanitizeHTML( __( 'If selected, the GBFS API endpoints (gbfs.json, station and vehicle feeds) are not registered, while the rest of the API stays active.', 'commonsbooking' ) ), + 'id' => 'gbfs-api-disabled', + 'type' => 'checkbox', + ), array( // Repeatable group -> API Shares diff --git a/includes/Users.php b/includes/Users.php index c3220544b..9b9f5272a 100644 --- a/includes/Users.php +++ b/includes/Users.php @@ -171,17 +171,7 @@ function commonsbooking_isCurrentUserAdmin() { return false; } $user = wp_get_current_user(); - $isAdmin = commonsbooking_isUserAdmin( $user ); - /** - * Default value if current user is admin. - * - * @since 2.10.0 add $user param - * @since 2.4.3 - * - * @param bool $isAdmin true or false, if current user is admin - * @param null|WP_User $user current user - */ - return apply_filters( 'commonsbooking_isCurrentUserAdmin', $isAdmin, $user ); + return commonsbooking_isUserAdmin( $user ); } /** @@ -195,12 +185,24 @@ function commonsbooking_isCurrentUserAdmin() { * @return bool */ function commonsbooking_isUserAdmin( \WP_User $user ) { + $isAdmin = false; foreach ( \CommonsBooking\Repository\UserRepository::getAdminRoles() as $adminRole ) { if ( in_array( $adminRole, $user->roles ) ) { - return true; + $isAdmin = true; + break; } } - return false; + /** + * Default value if user is admin. + * + * @since 2.11 changed from commonsbooking_isCurrentUserAdmin to commonsbooking_isUserAdmin + * @since 2.10.0 add $user param + * @since 2.4.3 + * + * @param bool $isAdmin true or false, if current user is admin + * @param null|WP_User $user current user + */ + return apply_filters( 'commonsbooking_isUserAdmin', $isAdmin, $user ); } /** diff --git a/includes/gbfs-json-schema/gbfs.json b/includes/gbfs-json-schema/gbfs.json index 2898226e2..0bd292143 100644 --- a/includes/gbfs-json-schema/gbfs.json +++ b/includes/gbfs-json-schema/gbfs.json @@ -1,6 +1,6 @@ { "$schema": "http://json-schema.org/draft-07/schema", - "$id": "https://github.com/MobilityData/gbfs-json-schema/blob/master/v3.1-RC2/gbfs.json", + "$id": "https://github.com/MobilityData/gbfs-json-schema/blob/master/v3.1-RC3/gbfs.json", "description": "Auto-discovery file that links to all of the other files published by the system.", "type": "object", "properties": { @@ -17,7 +17,7 @@ "version": { "description": "GBFS version number to which the feed conforms, according to the versioning framework (added in v1.1).", "type": "string", - "const": "3.1-RC2" + "const": "3.1-RC3" }, "data": { "type": "object", diff --git a/includes/gbfs-json-schema/station_information.json b/includes/gbfs-json-schema/station_information.json index d801ed3e6..8b9ca5700 100644 --- a/includes/gbfs-json-schema/station_information.json +++ b/includes/gbfs-json-schema/station_information.json @@ -1,7 +1,7 @@ { "$schema": "http://json-schema.org/draft-07/schema", "$id": - "https://github.com/MobilityData/gbfs-json-schema/blob/master/v3.1-RC2/station_information.json", + "https://github.com/MobilityData/gbfs-json-schema/blob/master/v3.1-RC3/station_information.json", "description": "List of all stations, their capacities and locations. REQUIRED of systems utilizing docks.", "type": "object", @@ -22,7 +22,7 @@ "description": "GBFS version number to which the feed conforms, according to the versioning framework (added in v1.1).", "type": "string", - "const": "3.1-RC2" + "const": "3.1-RC3" }, "data": { "description": @@ -107,7 +107,7 @@ "type": "string" }, "city": { - "description": "City where station is located. (added in v3.1-RC2)", + "description": "City where station is located. (added in v3.1-RC3)", "type": "string" }, "station_opening_hours": { diff --git a/includes/gbfs-json-schema/station_status.json b/includes/gbfs-json-schema/station_status.json index 7249ab6b8..19cf5e119 100644 --- a/includes/gbfs-json-schema/station_status.json +++ b/includes/gbfs-json-schema/station_status.json @@ -1,6 +1,6 @@ { "$schema": "http://json-schema.org/draft-07/schema", - "$id": "https://github.com/MobilityData/gbfs-json-schema/blob/master/v3.1-RC2/station_status.json", + "$id": "https://github.com/MobilityData/gbfs-json-schema/blob/master/v3.1-RC3/station_status.json", "description": "Describes the capacity and rental availability of the station", "type": "object", @@ -21,7 +21,7 @@ "description": "GBFS version number to which the feed conforms, according to the versioning framework (added in v1.1).", "type": "string", - "const": "3.1-RC2" + "const": "3.1-RC3" }, "data": { "description": diff --git a/includes/gbfs-json-schema/system_information.json b/includes/gbfs-json-schema/system_information.json index 1f29028f6..8c29b2d28 100644 --- a/includes/gbfs-json-schema/system_information.json +++ b/includes/gbfs-json-schema/system_information.json @@ -1,7 +1,7 @@ { "$schema": "http://json-schema.org/draft-07/schema", "$id": - "https://github.com/MobilityData/gbfs-json-schema/blob/master/v3.1-RC2/system_information.json", + "https://github.com/MobilityData/gbfs-json-schema/blob/master/v3.1-RC3/system_information.json", "description": "Details including system operator, system location, year implemented, URL, contact info, time zone.", "type": "object", @@ -22,7 +22,7 @@ "description": "GBFS version number to which the feed conforms, according to the versioning framework (added in v1.1).", "type": "string", - "const": "3.1-RC2" + "const": "3.1-RC3" }, "data": { "description": "Response data in the form of name:value pairs.", diff --git a/includes/gbfs-json-schema/vehicle_availability.json b/includes/gbfs-json-schema/vehicle_availability.json new file mode 100644 index 000000000..56ac9c593 --- /dev/null +++ b/includes/gbfs-json-schema/vehicle_availability.json @@ -0,0 +1,91 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://github.com/MobilityData/gbfs-json-schema/blob/master/v3.1-RC3/vehicle_availability.json", + "description": "Describes the vehicle availabilities of the system.", + "type": "object", + "properties": { + "last_updated": { + "description": "Last time the data in the feed was updated in RFC3339 format.", + "type": "string", + "format": "date-time" + }, + "ttl": { + "description": "Number of seconds before the data in the feed will be updated again (0 if the data should always be refreshed).", + "type": "integer", + "minimum": 0 + }, + "version": { + "description": "GBFS version number to which the feed conforms, according to the versioning framework (added in v1.1).", + "type": "string", + "const": "3.1-RC3" + }, + "data": { + "type": "object", + "properties": { + "vehicles": { + "type": "array", + "description": "Contains one object per vehicle.", + "items": { + "type": "object", + "properties": { + "vehicle_id": { + "type": "string", + "description": "Identifier of a vehicle" + }, + "vehicle_type_id": { + "type": "string", + "description": "Unique identifier of a vehicle type as defined in vehicle_types.json" + }, + "station_id": { + "type": "string", + "description": " The id of the station where this vehicle is located when available" + }, + "pricing_plan_id": { + "type": "string", + "description": "The plan_id of the pricing plan this vehicle is eligible for" + }, + "vehicle_equipment": { + "type": "array", + "description": "List of vehicle equipment provided by the operator", + "items": { + "type": "string" + } + }, + "availabilities": { + "type": "array", + "description": "Array of time slots during which the specified vehicle is available.", + "items": { + "type": "object", + "properties": { + "from": { + "type": "string", + "description": "Start date and time of available time slot.", + "format": "date-time" + }, + "until": { + "type": "string", + "description": "End date and time of available time slot.", + "format": "date-time" + } + }, + "required": ["from"], + "additionalProperties": false + } + } + }, + "required": [ + "vehicle_id", + "station_id", + "availabilities" + ], + "additionalProperties": false + } + } + }, + "required": ["vehicles"], + "additionalProperties": false + } + }, + "required": ["last_updated", "ttl", "version", "data"], + "additionalProperties": false +} diff --git a/includes/gbfs-json-schema/vehicle_status.json b/includes/gbfs-json-schema/vehicle_status.json new file mode 100644 index 000000000..87e280408 --- /dev/null +++ b/includes/gbfs-json-schema/vehicle_status.json @@ -0,0 +1,153 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "$id": + "https://github.com/MobilityData/gbfs-json-schema/blob/master/v3.1-RC3/vehicle_status.json", + "description": + "Describes the vehicles that are available for rent (as of v3.0, formerly free_bike_status).", + "type": "object", + "properties": { + "last_updated": { + "description": + "Last time the data in the feed was updated in RFC3339 format.", + "type": "string", + "format": "date-time" + }, + "ttl": { + "description": + "Number of seconds before the data in the feed will be updated again (0 if the data should always be refreshed).", + "type": "integer", + "minimum": 0 + }, + "version": { + "description": + "GBFS version number to which the feed conforms, according to the versioning framework (added in v1.1).", + "type": "string", + "const": "3.1-RC3" + }, + "data": { + "description": + "Array that contains one object per vehicle as defined below.", + "type": "object", + "properties": { + "vehicles": { + "type": "array", + "items": { + "type": "object", + "properties": { + "vehicle_id": { + "description": "Rotating (as of v2.0) identifier of a vehicle.", + "type": "string" + }, + "lat": { + "description": "The latitude of the vehicle.", + "type": "number", + "minimum": -90, + "maximum": 90 + }, + "lon": { + "description": "The longitude of the vehicle.", + "type": "number", + "minimum": -180, + "maximum": 180 + }, + "is_reserved": { + "description": "Is the vehicle currently reserved?", + "type": "boolean" + }, + "is_disabled": { + "description": "Is the vehicle currently disabled (broken)?", + "type": "boolean" + }, + "rental_uris": { + "description": "Contains rental uris for Android, iOS, and web in the android, ios, and web fields (added in v1.1).", + "type": "object", + "properties": { + "android": { + "description": "URI that can be passed to an Android app with an intent (added in v1.1).", + "type": "string", + "format": "uri" + }, + "ios": { + "description": "URI that can be used on iOS to launch the rental app for this vehicle (added in v1.1).", + "type": "string", + "format": "uri" + }, + "web": { + "description": "URL that can be used by a web browser to show more information about renting this vehicle (added in v1.1).", + "type": "string", + "format": "uri" + } + } + }, + "vehicle_type_id": { + "description": "The vehicle_type_id of this vehicle (added in v2.1-RC).", + "type": "string" + }, + "last_reported": { + "description": "The last time this vehicle reported its status to the operator's backend in RFC3339 format (added in v2.1-RC).", + "type": "string", + "format": "date-time" + }, + "current_range_meters": { + "description": "The furthest distance in meters that the vehicle can travel without recharging or refueling with the vehicle's current charge or fuel (added in v2.1-RC).", + "type": "number", + "minimum": 0 + }, + "current_fuel_percent": { + "description": "This value represents the current percentage, expressed from 0 to 1, of fuel or battery power remaining in the vehicle. Added in v2.3-RC.", + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "station_id": { + "description": "Identifier referencing the station_id if the vehicle is currently at a station (added in v2.1-RC2).", + "type": "string" + }, + "home_station_id": { + "description": "The station_id of the station this vehicle must be returned to (added in v2.3-RC).", + "type": "string" + }, + "pricing_plan_id": { + "description": "The plan_id of the pricing plan this vehicle is eligible for (added in v2.2).", + "type": "string" + }, + "vehicle_equipment": { + "description": "List of vehicle equipment provided by the operator in addition to the accessories already provided in the vehicle. Added in v2.3.", + "type": "array", + "items": { + "enum": ["child_seat_a", "child_seat_b", "child_seat_c", "winter_tires", "snow_chains"] + } + }, + "available_until": { + "description": "The date and time when any rental of the vehicle must be completed. Added in v2.3.", + "type": "string", + "pattern": "^([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})(([+-]([0-9]{2}):([0-9]{2}))|Z)$" + } + }, + "anyOf": [ + { + "required": ["lat", "lon"], + "errorMessage": "Both 'lat' and 'lon' are required." + }, + { + "required": ["station_id"], + "properties": { + "lat": { + "not": {} + }, + "lon": { + "not": {} + } + }, + "errorMessage": "'station_id' is required if 'lat' and 'lon' are not present." + } + ], + "required": ["vehicle_id", "is_reserved", "is_disabled"] + } + } + }, + "required": ["vehicles"] + } + }, + "required": ["last_updated", "ttl", "version", "data"] +} diff --git a/includes/gbfs-json-schema/vehicle_types.json b/includes/gbfs-json-schema/vehicle_types.json new file mode 100644 index 000000000..02eb9644c --- /dev/null +++ b/includes/gbfs-json-schema/vehicle_types.json @@ -0,0 +1,273 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "$id": + "https://github.com/MobilityData/gbfs-json-schema/blob/master/v3.1-RC3/vehicle_types.json", + "description": + "Describes the types of vehicles that System operator has available for rent (added in v2.1-RC).", + "type": "object", + "properties": { + "last_updated": { + "description": + "Last time the data in the feed was updated in RFC3339 format.", + "type": "string", + "format": "date-time" + }, + "ttl": { + "description": + "Number of seconds before the data in the feed will be updated again (0 if the data should always be refreshed).", + "type": "integer", + "minimum": 0 + }, + "version": { + "description": + "GBFS version number to which the feed conforms, according to the versioning framework.", + "type": "string", + "const": "3.1-RC3" + }, + "data": { + "description": "Response data in the form of name:value pairs.", + "type": "object", + "properties": { + "vehicle_types": { + "description": + "Array that contains one object per vehicle type in the system as defined below.", + "type": "array", + "items": { + "type": "object", + "properties": { + "vehicle_type_id": { + "description": "Unique identifier of a vehicle type.", + "type": "string" + }, + "form_factor": { + "description": "The vehicle's general form factor.", + "type": "string", + "enum": ["bicycle", "cargo_bicycle" ,"car", "moped", "scooter_standing", "scooter_seated", "other"] + }, + "rider_capacity": { + "description": "The number of riders (driver included) the vehicle can legally accommodate", + "type": "integer", + "minimum": 0 + }, + "cargo_volume_capacity": { + "description": "Cargo volume available in the vehicle, expressed in liters.", + "type": "integer", + "minimum": 0 + }, + "cargo_load_capacity": { + "description": "The capacity of the vehicle cargo space (excluding passengers), expressed in kilograms.", + "type": "integer", + "minimum": 0 + }, + + "propulsion_type": { + "description": "The primary propulsion type of the vehicle. Updated in v2.3 to represent car-sharing", + "type": "string", + "enum": ["human", "electric_assist", "electric", "combustion", "combustion_diesel", "hybrid", "plug_in_hybrid", "hydrogen_fuel_cell"] + }, + "eco_labels": { + "description": "Vehicle air quality certificate. added in v2.3.", + "type": "array", + "items": { + "type": "object", + "properties": { + "country_code": { + "description": " Country code following the ISO 3166-1 alpha-2 notation. Added in v2.3.", + "type": "string", + "pattern": "^[A-Z]{2}" + }, + "eco_sticker": { + "description": " Name of the eco label. Added in v2.3.", + "type": "string" + } + }, + "required": ["country_code", "eco_sticker"] + } + }, + "max_range_meters": { + "description": + "The furthest distance in meters that the vehicle can travel without recharging or refueling when it has the maximum amount of energy potential.", + "type": "number", + "minimum": 0 + }, + "name": { + "description": "The public name of this vehicle type. An array with one object per supported language with the following keys:", + "type": "array", + "items": { + "type": "object", + "properties": { + "text": { + "description": "The translated text.", + "type": "string" + }, + "language": { + "description": "IETF BCP 47 language code.", + "type": "string", + "pattern": "^[a-z]{2,3}(-[A-Z]{2})?$" + } + }, + "required": ["text", "language"] + } + }, + "vehicle_accessories": { + "description": "Description of accessories available in the vehicle.", + "type": "array", + "items": { + "enum": ["air_conditioning", "automatic", "manual", "convertible", "cruise_control", "doors_2", "doors_3", "doors_4", "doors_5", "navigation"] + } + }, + "g_CO2_km": { + "description": "Maximum quantity of CO2, in grams, emitted per kilometer, according to the WLTP. Added in v2.3", + "type": "integer", + "minimum": 0 + }, + "vehicle_image": { + "description": "URL to an image that would assist the user in identifying the vehicle. JPEG or PNG. Added in v2.3", + "type": "string", + "format": "uri" + }, + "make": { + "description": "The name of the vehicle manufacturer. An array with one object per supported language with the following keys:", + "type": "array", + "items": { + "type": "object", + "properties": { + "text": { + "description": "The translated text.", + "type": "string" + }, + "language": { + "description": "IETF BCP 47 language code.", + "type": "string", + "pattern": "^[a-z]{2,3}(-[A-Z]{2})?$" + } + }, + "required": ["text", "language"] + } + }, + "model": { + "description": "The name of the vehicle model. An array with one object per supported language with the following keys:", + "type": "array", + "items": { + "type": "object", + "properties": { + "text": { + "description": "The translated text.", + "type": "string" + }, + "language": { + "description": "IETF BCP 47 language code.", + "type": "string", + "pattern": "^[a-z]{2,3}(-[A-Z]{2})?$" + } + }, + "required": ["text", "language"] + } + }, + "color": { + "description": "The color of the vehicle. Added in v2.3", + "type": "string" + }, + "description": { + "description": "Customer-readable description of the vehicle type outlining special features or how-tos. An array with one object per supported language with the following keys:", + "type": "array", + "items": { + "type": "object", + "properties": { + "text": { + "description": "The translated text.", + "type": "string" + }, + "language": { + "description": "IETF BCP 47 language code.", + "type": "string", + "pattern": "^[a-z]{2,3}(-[A-Z]{2})?$" + } + }, + "required": ["text", "language"] + } + }, + "wheel_count": { + "description": "Number of wheels this vehicle type has. Added in v2.3", + "type": "integer", + "minimum": 0 + }, + "max_permitted_speed": { + "description": "The maximum speed in kilometers per hour this vehicle is permitted to reach in accordance with local permit and regulations. Added in v2.3", + "type": "integer", + "minimum": 0 + }, + "rated_power": { + "description": "The rated power of the motor for this vehicle type in watts. Added in v2.3", + "type": "integer", + "minimum": 0 + }, + "default_reserve_time": { + "description": "Maximum time in minutes that a vehicle can be reserved before a rental begins added in v2.3-RC.", + "type": "integer", + "minimum": 0 + }, + "return_constraint": { + "description": "The conditions for returning the vehicle at the end of the trip. Added in v2.3-RC as return_type, and updated to return_constraint in v2.3.", + "type": "string", + "enum": ["free_floating", "roundtrip_station", "any_station", "hybrid"] + }, + "min_age": { + "description": "Minimum age required to use this vehicle. Added in v3.1-RC3.", + "type": "integer", + "minimum": 0 + }, + "vehicle_assets": { + "description": "An object where each key defines one of the items listed below added in v2.3-RC.", + "type": "object", + "properties": { + "icon_url": { + "description": "A fully qualified URL pointing to the location of a graphic icon file that MAY be used to represent this vehicle type on maps and in other applications added in v2.3-RC.", + "type": "string", + "format": "uri" + }, + "icon_url_dark": { + "description": "A fully qualified URL pointing to the location of a graphic icon file to be used to represent this vehicle type when in dark mode added in v2.3-RC.", + "type": "string", + "format": "uri" + }, + "icon_last_modified": { + "description": "Date that indicates the last time any included vehicle icon images were modified or updated added in v2.3-RC.", + "type": "string", + "format": "date" + } + }, + "required": ["icon_url", "icon_last_modified"] + }, + "default_pricing_plan_id": { + "description": "A plan_id as defined in system_pricing_plans.json added in v2.3-RC.", + "type": "string" + }, + "pricing_plan_ids": { + "description": "Array of all pricing plan IDs as defined in system_pricing_plans.json added in v2.3-RC.", + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": ["vehicle_type_id", "form_factor", "propulsion_type"], + "if": { + "properties": { + "propulsion_type": { + "enum": ["electric", "electric_assist", "combustion", "combustion_diesel", "hybrid", "plug_in_hybrid", "hydrogen_fuel_cell"] + } + } + }, + "then": { + "required": ["max_range_meters"] + } + } + } + }, + "required": ["vehicle_types"] + } + }, + "required": ["last_updated", "ttl", "version", "data"] +} + diff --git a/languages/commonsbooking-de_DE.mo b/languages/commonsbooking-de_DE.mo index c79a46cd8..fae1c549b 100644 Binary files a/languages/commonsbooking-de_DE.mo and b/languages/commonsbooking-de_DE.mo differ diff --git a/languages/commonsbooking-de_DE.po b/languages/commonsbooking-de_DE.po index 0be42d0b2..396c05a88 100644 --- a/languages/commonsbooking-de_DE.po +++ b/languages/commonsbooking-de_DE.po @@ -8,10 +8,10 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "POT-Creation-Date: 2023-09-15T04:04:14+02:00\n" -"PO-Revision-Date: 2026-02-19 18:07+0100\n" +"PO-Revision-Date: 2026-06-17 15:48+0200\n" "Language: de_DE\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Poedit 3.8\n" +"X-Generator: Poedit 3.9\n" #. Plugin Name of the plugin #: commonsbooking.php @@ -510,8 +510,8 @@ msgid "The color used for dark text on light backgrounds" msgstr "Die Farbe, die für dunklen Text auf hellem Hintergrund verwendet wird" #: includes/OptionsArray.php:644 -#: src/Wordpress/CustomPostType/Restriction.php:305 -#: src/Wordpress/CustomPostType/Restriction.php:326 +#: src/Wordpress/CustomPostType/Restriction.php:287 +#: src/Wordpress/CustomPostType/Restriction.php:308 #: templates/dashboard-index.php:47 msgid "Restrictions" msgstr "Einschränkungen" @@ -809,7 +809,7 @@ msgstr "Zeitrahmen-Export herunterladen" #: includes/OptionsArray.php:1321 #: src/Wordpress/CustomPostType/Map.php:557 #: src/Wordpress/CustomPostType/Restriction.php:47 -#: src/Wordpress/CustomPostType/Restriction.php:415 +#: src/Wordpress/CustomPostType/Restriction.php:397 #: src/Wordpress/CustomPostType/Timeframe.php:98 #: src/Wordpress/CustomPostType/Timeframe.php:455 msgid "Type" @@ -1006,71 +1006,71 @@ msgstr "Erlaubt die Anpassung der Optionen für das Caching-System" msgid "Current connection status" msgstr "Aktueller Verbindungsstatus" -#: src/CB/CB1UserFields.php:69 +#: src/CB/CB1UserFields.php:72 msgid "First Name" msgstr "Vorname" -#: src/CB/CB1UserFields.php:72 +#: src/CB/CB1UserFields.php:75 msgid "Please enter your first name" msgstr "Bitte gib deinen Vornamen ein" -#: src/CB/CB1UserFields.php:76 +#: src/CB/CB1UserFields.php:79 msgid "Last Name" msgstr "Nachname" -#: src/CB/CB1UserFields.php:79 +#: src/CB/CB1UserFields.php:82 msgid "Please enter your last name" msgstr "Bitte gib Deinen Nachnamen ein" -#: src/CB/CB1UserFields.php:83 +#: src/CB/CB1UserFields.php:86 msgid "Phone Number" msgstr "Telefonnummer" -#: src/CB/CB1UserFields.php:86 +#: src/CB/CB1UserFields.php:89 msgid "Please enter your phone number" msgstr "Bitte gib Deine Telefonnummer ein" -#: src/CB/CB1UserFields.php:90 -#: src/CB/CB1UserFields.php:279 +#: src/CB/CB1UserFields.php:93 +#: src/CB/CB1UserFields.php:283 #: src/Wordpress/CustomPostType/Location.php:237 #: templates/booking-single.php:77 msgid "Address" msgstr "Adresse" -#: src/CB/CB1UserFields.php:93 +#: src/CB/CB1UserFields.php:96 msgid "Please enter your address" msgstr "Bitte gib deine Adresse ein" -#: src/CB/CB1UserFields.php:96 +#: src/CB/CB1UserFields.php:99 msgid "Terms and Conditions" msgstr "Nutzungsbedingungen" -#: src/CB/CB1UserFields.php:99 +#: src/CB/CB1UserFields.php:102 msgid "I accept the terms & conditions" msgstr "Ich akzeptiere die Nutzungsbedingungen" -#: src/CB/CB1UserFields.php:100 +#: src/CB/CB1UserFields.php:103 msgid "Please accept the terms & conditions" msgstr "Bitte akzeptiere die Nutzungsbedingungen" -#: src/CB/CB1UserFields.php:188 +#: src/CB/CB1UserFields.php:191 #, php-format msgid "Read the terms and services" msgstr "Lies die Nutzungsbedingungen" -#: src/CB/CB1UserFields.php:267 +#: src/CB/CB1UserFields.php:271 msgid "Extra Fields" msgstr "Zusatzfelder" -#: src/CB/CB1UserFields.php:271 +#: src/CB/CB1UserFields.php:275 msgid "Phone number" msgstr "Telefonnummer" -#: src/CB/CB1UserFields.php:287 +#: src/CB/CB1UserFields.php:291 msgid "Terms and conditions" msgstr "Nutzungsbedingungen" -#: src/CB/CB1UserFields.php:297 +#: src/CB/CB1UserFields.php:301 msgid "Accepted Terms & Conditions" msgstr "Nutzungsbedingungen akzeptiert" @@ -1179,56 +1179,56 @@ msgstr "Link zu deiner Buchung" msgid "Please contact the contact persons at the location directly if you have any questions regarding collection or return:" msgstr "Bitte kontaktiere die Kontaktpersonen vor Ort direkt, wenn du Fragen zur Abholung oder Rückgabe hast:" -#: src/Model/Restriction.php:244 -#: src/Model/Restriction.php:268 +#: src/Model/Restriction.php:248 +#: src/Model/Restriction.php:275 msgid "Not set" msgstr "Nicht gesetzt" -#: src/Model/Timeframe.php:255 +#: src/Model/Timeframe.php:331 msgid "Available here" msgstr "Hier verfügbar" #. translators: %s = date in WordPress defined format #: src/Model/Booking.php:437 -#: src/Model/Timeframe.php:260 +#: src/Model/Timeframe.php:347 #, php-format msgid "on %s" msgstr "am %s" #. translators: %s = date in WordPress defined format -#: src/Model/Timeframe.php:265 +#: src/Model/Timeframe.php:339 #, php-format msgid "from %s" msgstr "von %s" -#: src/Model/Timeframe.php:269 +#: src/Model/Timeframe.php:343 msgid "permanently" msgstr "dauerhaft" #. translators: %1 = startdate, %2 = enddate in WordPress defined format #. translators: %1$s = startdate, second %2$s = enddate in WordPress defined format #: src/Model/Booking.php:440 -#: src/Model/Timeframe.php:275 +#: src/Model/Timeframe.php:352 #, php-format msgid "from %1$s until %2$s" msgstr "von %1$s bis %2$s" #. translators: %s = enddate in WordPress defined format -#: src/Model/Timeframe.php:282 +#: src/Model/Timeframe.php:359 #, php-format msgid "until %s" msgstr "bis %s" -#: src/Model/Timeframe.php:610 +#: src/Model/Timeframe.php:687 msgid "A pickup time but no return time has been set. Please set the return time." msgstr "Eine Abholzeit, aber keine Rückgabezeit wurde festgelegt. Lege bitte eine Rückgabezeit fest." -#: src/Model/Timeframe.php:620 +#: src/Model/Timeframe.php:697 msgid "End date is before start date. Please set a valid end date." msgstr "Enddatum liegt vor dem Startdatum. Bitte setze ein gültiges Enddatum." #. translators: %1$s = timeframe-ID, %2$s is timeframe post_title -#: src/Model/Timeframe.php:655 +#: src/Model/Timeframe.php:732 #, php-format msgid "Item is already bookable at another location within the same date range. See other timeframe ID: %1$s: %2$s" msgstr "Artikel ist bereits an einem anderen Ort innerhalb desselben Datumsbereichs buchbar. Siehe andere Zeitrahmen ID: %1$s: %2$s" @@ -1243,8 +1243,8 @@ msgstr "Artikel-Kategorien" msgid "Location Categories" msgstr "Standort-Kategorien" -#: src/Wordpress/CustomPostType/Item.php:324 -#: src/Wordpress/CustomPostType/Item.php:344 +#: src/Wordpress/CustomPostType/Item.php:334 +#: src/Wordpress/CustomPostType/Item.php:354 msgid "Item Category" msgstr "Artikel-Kategorie" @@ -1275,15 +1275,15 @@ msgid "Directory %s could not be written to." msgstr "Der Ordner %s ist nicht beschreibbar." #: src/View/Admin/Filter.php:58 -#: src/Wordpress/CustomPostType/Booking.php:779 -#: src/Wordpress/CustomPostType/Restriction.php:451 +#: src/Wordpress/CustomPostType/Booking.php:792 +#: src/Wordpress/CustomPostType/Restriction.php:433 #: src/Wordpress/CustomPostType/Timeframe.php:678 msgid "Start date" msgstr "Startdatum" #: src/View/Admin/Filter.php:62 -#: src/Wordpress/CustomPostType/Booking.php:796 -#: src/Wordpress/CustomPostType/Restriction.php:461 +#: src/Wordpress/CustomPostType/Booking.php:809 +#: src/Wordpress/CustomPostType/Restriction.php:443 #: src/Wordpress/CustomPostType/Timeframe.php:702 msgid "End date" msgstr "Enddatum" @@ -1307,7 +1307,7 @@ msgstr "Nicht verfügbar" #: src/View/Booking.php:196 #: src/View/MassOperations.php:38 -#: src/Wordpress/CustomPostType/Booking.php:446 +#: src/Wordpress/CustomPostType/Booking.php:459 #: src/Wordpress/CustomPostType/Timeframe.php:97 #: templates/shortcode-bookings.php:74 msgid "User" @@ -1315,8 +1315,8 @@ msgstr "Nutzende*r" #: src/View/Booking.php:200 #: src/View/MassOperations.php:42 -#: src/Wordpress/CustomPostType/Booking.php:973 -#: src/Wordpress/CustomPostType/Restriction.php:477 +#: src/Wordpress/CustomPostType/Booking.php:986 +#: src/Wordpress/CustomPostType/Restriction.php:459 msgid "Status" msgstr "Status" @@ -1332,29 +1332,29 @@ msgstr "Die Datei wird als .txt Datei durch Tabstopp getrennt exportiert, sodass msgid "Booking codes list" msgstr "Liste der Buchungscodes" -#: src/View/Calendar.php:233 -#: src/Wordpress/CustomPostType/Booking.php:447 -#: src/Wordpress/CustomPostType/Booking.php:761 -#: src/Wordpress/CustomPostType/Booking.php:989 +#: src/View/Calendar.php:237 +#: src/Wordpress/CustomPostType/Booking.php:460 +#: src/Wordpress/CustomPostType/Booking.php:774 +#: src/Wordpress/CustomPostType/Booking.php:1002 #: src/Wordpress/CustomPostType/Item.php:117 #: src/Wordpress/CustomPostType/Restriction.php:48 -#: src/Wordpress/CustomPostType/Restriction.php:438 +#: src/Wordpress/CustomPostType/Restriction.php:420 #: src/Wordpress/CustomPostType/Timeframe.php:99 #: templates/shortcode-bookings.php:73 msgid "Item" msgstr "Artikel" -#: src/View/Calendar.php:177 +#: src/View/Calendar.php:181 msgid "No items found." msgstr "Keine Artikel gefunden." -#: src/View/Calendar.php:234 -#: src/Wordpress/CustomPostType/Booking.php:448 -#: src/Wordpress/CustomPostType/Booking.php:767 -#: src/Wordpress/CustomPostType/Booking.php:985 +#: src/View/Calendar.php:238 +#: src/Wordpress/CustomPostType/Booking.php:461 +#: src/Wordpress/CustomPostType/Booking.php:780 +#: src/Wordpress/CustomPostType/Booking.php:998 #: src/Wordpress/CustomPostType/Location.php:139 #: src/Wordpress/CustomPostType/Restriction.php:49 -#: src/Wordpress/CustomPostType/Restriction.php:431 +#: src/Wordpress/CustomPostType/Restriction.php:413 #: src/Wordpress/CustomPostType/Timeframe.php:100 #: src/Wordpress/CustomPostType/Timeframe.php:463 #: templates/shortcode-bookings.php:75 @@ -1503,189 +1503,189 @@ msgstr "Standort existiert nicht. (%s)" msgid "Start- and/or end-date is missing." msgstr "Das Start- und/oder Enddatum fehlt." -#: src/Wordpress/CustomPostType/Booking.php:307 +#: src/Wordpress/CustomPostType/Booking.php:320 msgid "Booking canceled." msgstr "Buchung storniert." #: src/Wordpress/CustomPostType/Booking.php:291 -#: src/Wordpress/CustomPostType/Booking.php:323 +#: src/Wordpress/CustomPostType/Booking.php:336 msgid "There is already a booking in this time-range. This notice may also appear if there is an unconfirmed booking in the requested period. Unconfirmed bookings are deleted after about 10 minutes. Please try again in a few minutes." msgstr "Es gibt bereits eine Buchung in diesem Zeitraum. Dieser Hinweis kann auch erscheinen, wenn es eine unbestätigte Buchung in dem gewünschten Zeitraum gibt. Unbestätigte Buchungen werden nach etwa 10 Minuten gelöscht. Bitte versuche es in ein paar Minuten erneut." -#: src/Wordpress/CustomPostType/Booking.php:331 -#: src/Wordpress/CustomPostType/Booking.php:524 -#: src/Wordpress/CustomPostType/Booking.php:712 +#: src/Wordpress/CustomPostType/Booking.php:344 +#: src/Wordpress/CustomPostType/Booking.php:537 +#: src/Wordpress/CustomPostType/Booking.php:725 #: src/Wordpress/CustomPostType/Timeframe.php:132 msgid "Booking" msgstr "Buchung" -#: src/Wordpress/CustomPostType/Booking.php:375 +#: src/Wordpress/CustomPostType/Booking.php:388 msgid "There was an error while saving the booking. Please try again. Thrown error:" msgstr "Es gab einen Fehler während der Buchung. Geworfener Fehler:" -#: src/Wordpress/CustomPostType/Booking.php:392 +#: src/Wordpress/CustomPostType/Booking.php:405 msgid "There was an error while saving the booking. Please try again. Resulting WP_ERROR: " msgstr "Es gab einen Fehler während der Buchung. WP_ERROR: " -#: src/Wordpress/CustomPostType/Booking.php:449 +#: src/Wordpress/CustomPostType/Booking.php:462 msgid "Bookingdate" msgstr "Buchungsdatum" -#: src/Wordpress/CustomPostType/Booking.php:450 +#: src/Wordpress/CustomPostType/Booking.php:463 #: src/Wordpress/CustomPostType/Restriction.php:50 #: src/Wordpress/CustomPostType/Timeframe.php:101 #: src/Wordpress/CustomPostType/Timeframe.php:758 msgid "Start Date" msgstr "Startdatum" -#: src/Wordpress/CustomPostType/Booking.php:451 +#: src/Wordpress/CustomPostType/Booking.php:464 #: src/Wordpress/CustomPostType/Restriction.php:51 #: src/Wordpress/CustomPostType/Timeframe.php:102 msgid "End Date" msgstr "Enddatum" -#: src/Wordpress/CustomPostType/Booking.php:452 +#: src/Wordpress/CustomPostType/Booking.php:465 msgid "Booking Status" msgstr "Buchungsstatus" -#: src/Wordpress/CustomPostType/Booking.php:453 -#: src/Wordpress/CustomPostType/Booking.php:981 +#: src/Wordpress/CustomPostType/Booking.php:466 +#: src/Wordpress/CustomPostType/Booking.php:994 #: src/Wordpress/CustomPostType/Timeframe.php:448 msgid "Comment" msgstr "Kommentar" -#: src/Wordpress/CustomPostType/Booking.php:523 +#: src/Wordpress/CustomPostType/Booking.php:536 #: templates/dashboard-index.php:45 msgid "Bookings" msgstr "Buchungen" -#: src/Wordpress/CustomPostType/Booking.php:525 +#: src/Wordpress/CustomPostType/Booking.php:538 #: src/Wordpress/CustomPostType/Item.php:118 #: src/Wordpress/CustomPostType/Location.php:140 -#: src/Wordpress/CustomPostType/Restriction.php:307 -#: src/Wordpress/CustomPostType/Timeframe.php:1152 +#: src/Wordpress/CustomPostType/Restriction.php:289 +#: src/Wordpress/CustomPostType/Timeframe.php:1153 msgid "Add new" msgstr "Neu hinzufügen" -#: src/Wordpress/CustomPostType/Booking.php:526 -#: src/Wordpress/CustomPostType/Booking.php:528 +#: src/Wordpress/CustomPostType/Booking.php:539 +#: src/Wordpress/CustomPostType/Booking.php:541 msgid "Add new booking" msgstr "Neue Buchung hinzufügen" -#: src/Wordpress/CustomPostType/Booking.php:527 -#: src/Wordpress/CustomPostType/Booking.php:743 +#: src/Wordpress/CustomPostType/Booking.php:540 +#: src/Wordpress/CustomPostType/Booking.php:756 msgid "Edit booking" msgstr "Buchung bearbeiten" -#: src/Wordpress/CustomPostType/Booking.php:529 +#: src/Wordpress/CustomPostType/Booking.php:542 msgid "Show booking" msgstr "Buchung anzeigen" -#: src/Wordpress/CustomPostType/Booking.php:530 +#: src/Wordpress/CustomPostType/Booking.php:543 msgid "Show bookings" msgstr "Buchungen anzeigen" -#: src/Wordpress/CustomPostType/Booking.php:531 +#: src/Wordpress/CustomPostType/Booking.php:544 msgid "Search bookings" msgstr "Buchungen suchen" -#: src/Wordpress/CustomPostType/Timeframe.php:1159 +#: src/Wordpress/CustomPostType/Timeframe.php:1160 msgid "Timeframes not found" msgstr "Zeitrahmen wurden nicht gefunden" -#: src/Wordpress/CustomPostType/Booking.php:533 +#: src/Wordpress/CustomPostType/Booking.php:546 msgid "No bookings found in trash" msgstr "Keine Buchungen im Papierkorb gefunden" -#: src/Wordpress/CustomPostType/Booking.php:534 +#: src/Wordpress/CustomPostType/Booking.php:547 msgid "Parent bookings:" msgstr "Übergeordnete Buchungen:" -#: src/Wordpress/CustomPostType/Booking.php:535 +#: src/Wordpress/CustomPostType/Booking.php:548 msgid "All bookings" msgstr "Alle Buchungen" -#: src/Wordpress/CustomPostType/Booking.php:536 -#: src/Wordpress/CustomPostType/Timeframe.php:1163 +#: src/Wordpress/CustomPostType/Booking.php:549 +#: src/Wordpress/CustomPostType/Timeframe.php:1164 msgid "Timeframe archive" msgstr "Zeitrahmenarchiv" -#: src/Wordpress/CustomPostType/Booking.php:537 -#: src/Wordpress/CustomPostType/Timeframe.php:1164 +#: src/Wordpress/CustomPostType/Booking.php:550 +#: src/Wordpress/CustomPostType/Timeframe.php:1165 msgid "Timeframe attributes" msgstr "Zeitrahmenattribute" -#: src/Wordpress/CustomPostType/Booking.php:538 +#: src/Wordpress/CustomPostType/Booking.php:551 msgid "Add to booking" msgstr "Der Buchung hinzufügen" -#: src/Wordpress/CustomPostType/Booking.php:539 +#: src/Wordpress/CustomPostType/Booking.php:552 msgid "Added to booking" msgstr "Zur Buchung hinzugefügt" -#: src/Wordpress/CustomPostType/Booking.php:540 -#: src/Wordpress/CustomPostType/Timeframe.php:1167 +#: src/Wordpress/CustomPostType/Booking.php:553 +#: src/Wordpress/CustomPostType/Timeframe.php:1168 msgid "Timeframe image" msgstr "Zeitrahmenbild" -#: src/Wordpress/CustomPostType/Booking.php:541 +#: src/Wordpress/CustomPostType/Booking.php:554 msgid "set booking image" msgstr "Buchungsbild festlegen" -#: src/Wordpress/CustomPostType/Booking.php:542 +#: src/Wordpress/CustomPostType/Booking.php:555 msgid "remove booking image" msgstr "Buchungsbild entfernen" -#: src/Wordpress/CustomPostType/Booking.php:543 +#: src/Wordpress/CustomPostType/Booking.php:556 msgid "use as booking image" msgstr "als Buchungsbild verwenden" -#: src/Wordpress/CustomPostType/Booking.php:544 -#: src/Wordpress/CustomPostType/Timeframe.php:1150 -#: src/Wordpress/CustomPostType/Timeframe.php:1171 +#: src/Wordpress/CustomPostType/Booking.php:557 +#: src/Wordpress/CustomPostType/Timeframe.php:1151 +#: src/Wordpress/CustomPostType/Timeframe.php:1172 #: templates/dashboard-index.php:37 msgid "Timeframes" msgstr "Zeitrahmen" -#: src/Wordpress/CustomPostType/Booking.php:852 +#: src/Wordpress/CustomPostType/Booking.php:865 msgid "External comment" msgstr "Öffentlicher Kommentar" -#: src/Wordpress/CustomPostType/Booking.php:853 +#: src/Wordpress/CustomPostType/Booking.php:866 msgid "This comment can be seen by users in booking details. It can be set by users during the booking confirmation process if comments are enabled in settings." msgstr "Dieser Kommentar ist intern für Zeitrahmen wie buchbar, Reparatur, Urlaub. Wenn es sich um eine Buchung handelt, kann dieser Kommentar von den Benutzenden während des Buchungsbestätigungsprozesses eingegeben werden." -#: src/Wordpress/CustomPostType/Booking.php:858 +#: src/Wordpress/CustomPostType/Booking.php:871 #: templates/booking-single.php:131 msgid "Internal comment" msgstr "Interner Kommentar" -#: src/Wordpress/CustomPostType/Booking.php:859 +#: src/Wordpress/CustomPostType/Booking.php:872 msgid "This internal comment can only be seen in the backend by privileged users like admins or cb-managers" msgstr "Dieser interne Kommentar kann im Backend nur von autorisierten Nutzenden wie Admins oder CB-Managern gesehen werden" -#: src/Wordpress/CustomPostType/Booking.php:780 +#: src/Wordpress/CustomPostType/Booking.php:793 msgid "Set the start date. You must set the time to 00:00 if you want to book the full day " msgstr "Lege das Startdatum fest. Setze die Uhrzeit auf 00:00, wenn du den ganzen Tag buchen willst " -#: src/Wordpress/CustomPostType/Booking.php:797 +#: src/Wordpress/CustomPostType/Booking.php:810 msgid "Set the end date. You must set time to 23:59 if you want to book the full day" msgstr "Lege das Enddatum fest. Setze die Zeit auf 23:59 Uhr, wenn du den ganzen Tag buchen willst" -#: src/Wordpress/CustomPostType/Booking.php:813 +#: src/Wordpress/CustomPostType/Booking.php:826 #: templates/booking-single.php:59 msgid "Booking Code" msgstr "Buchungscode" -#: src/Wordpress/CustomPostType/Booking.php:819 +#: src/Wordpress/CustomPostType/Booking.php:832 msgid "Booking User" msgstr "Buchende Person" -#: src/Wordpress/CustomPostType/Booking.php:834 +#: src/Wordpress/CustomPostType/Booking.php:847 msgid "Admin Booking User" msgstr "Admin Booking Konto" -#: src/Wordpress/CustomPostType/Booking.php:845 +#: src/Wordpress/CustomPostType/Booking.php:858 msgid "This is the admin user who created or modified this booking." msgstr "Dies ist der/die Admin-Nutzende, der diese Buchung erstellt oder geändert hat." @@ -1792,7 +1792,7 @@ msgstr "E-Mail-Adresse des Artikelbetreuers" msgid "Email addresses to which notifications about a change of item status (restriction, breakdown) shall be sent. You can enter multiple addresses separated by commas." msgstr "E-Mail-Adressen die benachrichtigt werden soll, wenn eine Nutzungseinschränkung für den Artikel eingerichtet wurde (Hinweis oder Totalausfall). Es können mehrere Adressen durch Komma getrennt eingeben werden." -#: src/Wordpress/CustomPostType/Item.php:293 +#: src/Wordpress/CustomPostType/Item.php:303 msgid "Item Meta-Data" msgstr "Artikel Metadaten" @@ -2031,104 +2031,104 @@ msgstr "Filtern nach Standort " msgid "Filter By Status " msgstr "Filtern nach Status " -#: src/Wordpress/CustomPostType/Restriction.php:306 -#: src/Wordpress/CustomPostType/Restriction.php:387 +#: src/Wordpress/CustomPostType/Restriction.php:288 +#: src/Wordpress/CustomPostType/Restriction.php:369 msgid "Restriction" msgstr "Einschränkung" -#: src/Wordpress/CustomPostType/Restriction.php:308 -#: src/Wordpress/CustomPostType/Restriction.php:310 +#: src/Wordpress/CustomPostType/Restriction.php:290 +#: src/Wordpress/CustomPostType/Restriction.php:292 msgid "Add new Restriction" msgstr "Neue Einschränkung hinzufügen" -#: src/Wordpress/CustomPostType/Restriction.php:309 +#: src/Wordpress/CustomPostType/Restriction.php:291 msgid "Edit Restriction" msgstr "Einschränkung bearbeiten" -#: src/Wordpress/CustomPostType/Restriction.php:311 +#: src/Wordpress/CustomPostType/Restriction.php:293 msgid "Show Restriction" msgstr "Einschränkung anzeigen" -#: src/Wordpress/CustomPostType/Restriction.php:312 +#: src/Wordpress/CustomPostType/Restriction.php:294 msgid "Show Restrictions" msgstr "Einschränkungen anzeigen" -#: src/Wordpress/CustomPostType/Restriction.php:313 +#: src/Wordpress/CustomPostType/Restriction.php:295 msgid "Search Restrictions" msgstr "Einschränkungen suchen" -#: src/Wordpress/CustomPostType/Restriction.php:314 +#: src/Wordpress/CustomPostType/Restriction.php:296 msgid "Restrictions not found" msgstr "Einschränkungen nicht gefunden" -#: src/Wordpress/CustomPostType/Restriction.php:315 +#: src/Wordpress/CustomPostType/Restriction.php:297 msgid "No Restrictions found in trash" msgstr "Keine Einschränkungen im Papierkorb gefunden" -#: src/Wordpress/CustomPostType/Restriction.php:316 +#: src/Wordpress/CustomPostType/Restriction.php:298 msgid "Parent Restrictions:" msgstr "Übergeordnete Einschränkungen:" -#: src/Wordpress/CustomPostType/Restriction.php:317 +#: src/Wordpress/CustomPostType/Restriction.php:299 msgid "All Restrictions" msgstr "Alle Einschränkungen" -#: src/Wordpress/CustomPostType/Restriction.php:318 +#: src/Wordpress/CustomPostType/Restriction.php:300 msgid "Restriction archive" msgstr "Einschränkungsarchiv" -#: src/Wordpress/CustomPostType/Restriction.php:319 +#: src/Wordpress/CustomPostType/Restriction.php:301 msgid "Restriction attributes" msgstr "Einschränkungsattribute" -#: src/Wordpress/CustomPostType/Restriction.php:320 +#: src/Wordpress/CustomPostType/Restriction.php:302 msgid "Add to Restriction" msgstr "Zur Einschränkung hinzufügen" -#: src/Wordpress/CustomPostType/Restriction.php:321 +#: src/Wordpress/CustomPostType/Restriction.php:303 msgid "Added to Restriction" msgstr "Zur Einschränkung hinzugefügt" -#: src/Wordpress/CustomPostType/Restriction.php:322 +#: src/Wordpress/CustomPostType/Restriction.php:304 msgid "Restriction image" msgstr "Einschränkungs-Bild" -#: src/Wordpress/CustomPostType/Restriction.php:323 +#: src/Wordpress/CustomPostType/Restriction.php:305 msgid "set Restriction image" msgstr "Festlegen des Einschränkungsbilds" -#: src/Wordpress/CustomPostType/Restriction.php:324 +#: src/Wordpress/CustomPostType/Restriction.php:306 msgid "remove Restriction image" msgstr "Einschränkungsbild entfernen" -#: src/Wordpress/CustomPostType/Restriction.php:325 +#: src/Wordpress/CustomPostType/Restriction.php:307 msgid "use as Restriction image" msgstr "Verwendung als Einschränkungsbild" -#: src/Wordpress/CustomPostType/Restriction.php:434 -#: src/Wordpress/CustomPostType/Restriction.php:441 +#: src/Wordpress/CustomPostType/Restriction.php:416 +#: src/Wordpress/CustomPostType/Restriction.php:423 #: src/Wordpress/CustomPostType/Timeframe.php:815 #: templates/shortcode-bookings.php:55 msgid "All" msgstr "Alle" -#: src/Wordpress/CustomPostType/Restriction.php:445 +#: src/Wordpress/CustomPostType/Restriction.php:427 msgid "Hint" msgstr "Erläuterung" -#: src/Wordpress/CustomPostType/Restriction.php:447 +#: src/Wordpress/CustomPostType/Restriction.php:429 msgid "Please enter here a short information about the reason and possible effects of the usage restriction.
The explanation will be displayed on the article page and in the notification e-mail." msgstr "Bitte gib hier eine kurze Information über den Grund und mögliche Auswirkungen der Nutzungsbeschränkung ein.
Die Erklärung wird auf der Artikelseite und in der Benachrichtigungs-E-Mail angezeigt." -#: src/Wordpress/CustomPostType/Restriction.php:452 +#: src/Wordpress/CustomPostType/Restriction.php:434 msgid "Set the start date and time" msgstr "Startdatums und der Startzeit festlegen" -#: src/Wordpress/CustomPostType/Restriction.php:462 +#: src/Wordpress/CustomPostType/Restriction.php:444 msgid "Set the estimated end date and time" msgstr "Das geschätzte Enddatum und die geschätzten Endzeit festlegen" -#: src/Wordpress/CustomPostType/Restriction.php:480 +#: src/Wordpress/CustomPostType/Restriction.php:462 msgid "" "Choose status of this restriction.
\n" "\t\t\t\tSet to None if you want to deactivate the restriction.
\n" @@ -2140,31 +2140,31 @@ msgstr "" "Wähle den Status dieser Einschränkung aus.
Wähle Keine wenn du die Einschränkung deaktivieren möchtest.
Wähle Aktiv, wenn die Einschränkung aktiv ist.
Wähle Problem gelöst, wenn die Einschränkung nicht mehr besteht.
Je nach ausgewähltem Status erhalten betroffene Nutzende entsprechende Benachrichtigungs-E-Mails.\n" "Wähle den gewünschten Status aus und klicke dann auf die Schaltfläche \"Senden\", um die E-Mail zu senden. Commonsbooking -> Tab Restrictions" msgstr "Wichtig: Bitte speichere diese Einschränkung, bevor du auf den Senden-Button klickst. Abhängig vom Status der Einschränkung werden die entsprechenden Benachrichtigungen an alle betroffenen Nutzenden und Standortadministrierenden gesendet. Du kannst die E-Mail-Vorlagen über Optionen -> CommonsBooking -> Einschränkungen konfigurieren" -#: src/Wordpress/CustomPostType/Restriction.php:514 +#: src/Wordpress/CustomPostType/Restriction.php:496 msgid "Total breakdown" msgstr "Totalausfall" -#: src/Wordpress/CustomPostType/Restriction.php:515 +#: src/Wordpress/CustomPostType/Restriction.php:497 msgid "Notice" msgstr "Hinweis" -#: src/Wordpress/CustomPostType/Restriction.php:525 +#: src/Wordpress/CustomPostType/Restriction.php:507 msgid "Not active" msgstr "Nicht aktiv" -#: src/Wordpress/CustomPostType/Restriction.php:526 +#: src/Wordpress/CustomPostType/Restriction.php:508 msgid "Active" msgstr "Aktiv" -#: src/Wordpress/CustomPostType/Restriction.php:527 +#: src/Wordpress/CustomPostType/Restriction.php:509 msgid "Problem solved" msgstr "Problem gelöst" @@ -2185,7 +2185,7 @@ msgid "Blocked (not overbookable)" msgstr "Geblockt (nicht überbuchbar)" #: src/Wordpress/CustomPostType/Timeframe.php:420 -#: src/Wordpress/CustomPostType/Timeframe.php:1151 +#: src/Wordpress/CustomPostType/Timeframe.php:1152 msgid "Timeframe" msgstr "Zeitrahmen" @@ -2364,56 +2364,56 @@ msgstr "Monatlich" msgid "Yearly" msgstr "Jährlich" -#: src/Wordpress/CustomPostType/Timeframe.php:1153 -#: src/Wordpress/CustomPostType/Timeframe.php:1155 +#: src/Wordpress/CustomPostType/Timeframe.php:1154 +#: src/Wordpress/CustomPostType/Timeframe.php:1156 msgid "Add new timeframe" msgstr "Hinzufügen eines neuen Zeitrahmens" -#: src/Wordpress/CustomPostType/Timeframe.php:1154 +#: src/Wordpress/CustomPostType/Timeframe.php:1155 msgid "Edit timeframe" msgstr "Zeitrahmen bearbeiten" -#: src/Wordpress/CustomPostType/Timeframe.php:1156 +#: src/Wordpress/CustomPostType/Timeframe.php:1157 msgid "Show timeframe" msgstr "Zeitrahmen anzeigen" -#: src/Wordpress/CustomPostType/Timeframe.php:1157 +#: src/Wordpress/CustomPostType/Timeframe.php:1158 msgid "Show timeframes" msgstr "Zeitrahmen anzeigen" -#: src/Wordpress/CustomPostType/Timeframe.php:1158 +#: src/Wordpress/CustomPostType/Timeframe.php:1159 msgid "Search timeframes" msgstr "Zeitrahmen suchen" -#: src/Wordpress/CustomPostType/Timeframe.php:1160 +#: src/Wordpress/CustomPostType/Timeframe.php:1161 msgid "No timeframes found in trash" msgstr "Keine Zeitrahmen im Papierkorb gefunden" -#: src/Wordpress/CustomPostType/Timeframe.php:1161 +#: src/Wordpress/CustomPostType/Timeframe.php:1162 msgid "Parent timeframes:" msgstr "Übergeordnete Zeitrahmen:" -#: src/Wordpress/CustomPostType/Timeframe.php:1162 +#: src/Wordpress/CustomPostType/Timeframe.php:1163 msgid "All timeframes" msgstr "Alle Zeitrahmen" -#: src/Wordpress/CustomPostType/Timeframe.php:1165 +#: src/Wordpress/CustomPostType/Timeframe.php:1166 msgid "Add to timeframe" msgstr "Zum Zeitrahmen hinzufügen" -#: src/Wordpress/CustomPostType/Timeframe.php:1166 +#: src/Wordpress/CustomPostType/Timeframe.php:1167 msgid "Added to timeframe" msgstr "Zum Zeitrahmen hinzugefügt" -#: src/Wordpress/CustomPostType/Timeframe.php:1168 +#: src/Wordpress/CustomPostType/Timeframe.php:1169 msgid "set timeframe image" msgstr "Festlegen des Zeitrahmenbilds" -#: src/Wordpress/CustomPostType/Timeframe.php:1169 +#: src/Wordpress/CustomPostType/Timeframe.php:1170 msgid "remove timeframe image" msgstr "Zeitrahmenbild entfernen" -#: src/Wordpress/CustomPostType/Timeframe.php:1170 +#: src/Wordpress/CustomPostType/Timeframe.php:1171 msgid "use as timeframe image" msgstr "Verwendung als Zeitrahmenbild" @@ -3025,41 +3025,41 @@ msgstr "Es ist nicht möglich, diesen Zeitrahmen im Frontend abzurufen. Bitte be msgid "Cancelled" msgstr "Storniert" -#: src/Model/Timeframe.php:630 +#: src/Model/Timeframe.php:707 msgid "The start- and end-time of the timeframe can not be the same. Please check the full-day checkbox if you want users to be able to book the full day." msgstr "Die Start- und Endzeit des Zeitrahmens dürfen nicht gleich sein. Wenn der gesamte Tag buchbar sein soll muss die Option \"Ganzer Tag\" angewählt sein." #: src/Plugin.php:720 #: src/Plugin.php:735 -#: src/Wordpress/CustomPostType/Booking.php:936 +#: src/Wordpress/CustomPostType/Booking.php:949 msgid "CommonsBooking Bookings" msgstr "CommonsBooking Buchungen" -#: src/Wordpress/CustomPostType/Booking.php:532 +#: src/Wordpress/CustomPostType/Booking.php:545 msgid "Bookings not found" msgstr "Keine Buchungen gefunden" -#: src/Wordpress/CustomPostType/Booking.php:961 +#: src/Wordpress/CustomPostType/Booking.php:974 msgid "Booking start" msgstr "Buchungsbeginn" -#: src/Wordpress/CustomPostType/Booking.php:965 +#: src/Wordpress/CustomPostType/Booking.php:978 msgid "Booking end" msgstr "Buchungsende" -#: src/Wordpress/CustomPostType/Booking.php:969 +#: src/Wordpress/CustomPostType/Booking.php:982 msgid "Time of booking" msgstr "Buchungszeit" -#: src/Wordpress/CustomPostType/Booking.php:977 +#: src/Wordpress/CustomPostType/Booking.php:990 msgid "Booking code" msgstr "Buchungscode" -#: src/Wordpress/CustomPostType/Booking.php:993 +#: src/Wordpress/CustomPostType/Booking.php:1006 msgid "Time of cancellation" msgstr "Storniert am" -#: src/Wordpress/CustomPostType/Booking.php:997 +#: src/Wordpress/CustomPostType/Booking.php:1010 msgid "Admin booking by" msgstr "Adminbuchung von" @@ -3110,25 +3110,25 @@ msgid "If selected, days that are overbooked will be counted towards the maximum msgstr "Ist diese Option aktiviert, werden überbuchte Tage auf die maximale Anzahl buchbarer Tage angerechnet. Wenn diese Option deaktiviert ist, dann werden überbuchte Tage nicht zusätzlich gezählt und ermöglichen Buchungszeiträume die länger sind als die im Zeitrahmen konfigurierte maximale Anzahl an gebuchten Tagen." #. translators: first %s = timeframe-ID, second %s is timeframe post_title -#: src/Model/Timeframe.php:691 +#: src/Model/Timeframe.php:768 #, php-format msgid "See overlapping timeframe ID: %1$s %2$s" msgstr "Sich überschneidende Zeitrahmen ID: %1$s %2$s" -#: src/Model/Timeframe.php:790 +#: src/Model/Timeframe.php:867 msgid "Overlapping bookable timeframes are only allowed to have the same grid." msgstr "Sich überschneidende buchbare Zeiträume müssen das gleiche Raster haben." -#: src/Model/Timeframe.php:820 +#: src/Model/Timeframe.php:897 msgid "Overlapping bookable timeframes are not allowed to have the same weekdays." msgstr "Mehrere buchbare Zeiträume überschneiden sich in den definierten Wochentagen." -#: src/Model/Timeframe.php:832 +#: src/Model/Timeframe.php:909 msgid "Overlapping bookable timeframes are not allowed to have the same dates." msgstr "Mehrere buchbare Zeiträume überschneiden sich in dem definierten Datumsbereich." -#: src/Model/Timeframe.php:839 -#: src/Model/Timeframe.php:846 +#: src/Model/Timeframe.php:916 +#: src/Model/Timeframe.php:923 msgid "The other timeframe is overlapping with your weekly configuration." msgstr "Der andere Zeitrahmen überschneidet sich mit einer wöchentlichen Konfiguration." @@ -3168,7 +3168,7 @@ msgstr "Feiertage importieren" msgid "Select the year and state to import holidays for (as of now only German holidays are supported)" msgstr "Wählen Sie das Jahr und das Bundesland, für das Sie Feiertage importieren möchten (derzeit werden Feiertage in Deutschland unterstützt)" -#: src/Model/Timeframe.php:806 +#: src/Model/Timeframe.php:883 msgid "Daily repeated time periods are not allowed to overlap." msgstr "Täglich wiederholende Zeiträume dürfen sich nicht überschneiden." @@ -3318,11 +3318,11 @@ msgstr "Fehlende ID des Zeitrahmens" msgid "Error sending booking codes" msgstr "Fehler beim Senden von Buchungscodes" -#: src/View/BookingCodes.php:556 +#: src/View/BookingCodes.php:555 msgid "An unknown error occured" msgstr "Ein unbekannter Fehler ist aufgetreten" -#: src/View/BookingCodes.php:557 +#: src/View/BookingCodes.php:556 msgid "Email booking codes" msgstr "Buchungscodes per E-Mail versenden" @@ -3867,64 +3867,44 @@ msgstr "Bitte passe das Start- oder Enddatum an." msgid "Affected Bookings: %s" msgstr "Betroffene Buchungen: %s" -#: src/Model/Timeframe.php:555 +#: src/Model/Timeframe.php:632 msgid "Could not get item or location. Please set a valid item and location." msgstr "Artikel oder Standort konnte nicht gefunden werden. Bitte wähle einen gültigen Artikel oder Standort." -#: src/Model/Timeframe.php:564 +#: src/Model/Timeframe.php:641 msgid "Item or location is missing. Please set item and location." msgstr "Artikel oder Standort fehlen. Bitte Artikel und Standort festlegen." -#: src/Model/Timeframe.php:577 +#: src/Model/Timeframe.php:654 msgid "No dates selected. Please select at least one date." msgstr "Kein Datum ausgewählt. Bitte mindestens ein Datum auswählen." -#: src/Model/Timeframe.php:587 +#: src/Model/Timeframe.php:664 msgid "The same date was selected multiple times. Please select each date only once." msgstr "Das gleiche Datum wurde mehrere Male ausgewählt. Bitte ein Datum nur einmal auswählen." -#: src/Model/Timeframe.php:596 +#: src/Model/Timeframe.php:673 msgid "Startdate is missing. Please enter a start date to publish this timeframe." msgstr "Das Startdatum fehlt. Ein Startdatum muss eingegeben werden, damit der Zeitrahmen veröffentlicht werden kann." -#: src/View/Booking.php:581 -#: src/Wordpress/CustomPostType/Booking.php:864 +#: src/View/Booking.php:578 +#: src/Wordpress/CustomPostType/Booking.php:877 msgid "Submit booking" msgstr "Buchung abschicken" -#: src/Wordpress/CustomPostType/Booking.php:745 -msgid "" -"

Notice

In this view, you as an admin can create or modify existing bookings. Please use it with caution.
\n" -"\t\t\t\t

    \n" -"
  • Click on the preview button on the right panel to view more booking details and to cancel the booking via the cancel button.
  • \n" -"
  • Click on the Submit booking button at the end of the page to submit a new booking.
  • \n" -"
\n" -"\t\t\t\tPlease note: Only a few basic checks against existing bookings are performed. Please be wary of overlapping bookings.\n" -"

\n" -"\t\t\t\t" -msgstr "" -"

Achtung

In dieser Ansicht kannst du als Administrator*in Buchungen erstellen oder ändern. Bitte nutze die Möglichkeit mit Vorsicht.
\n" -"\t\t\t\t

    \n" -"
  • Klicke auf die Vorschau-Schaltfläche auf der rechten Seite, um weitere Buchungsdetails zu sehen und die Buchung über die Schaltfläche „Stornieren“ zu stornieren.
  • \n" -"
  • Klicke auf den Buchung abschicken Knopf am Ende der Seite um die Buchung zu bestätigen.
  • \n" -"
\n" -"\t\t\t\tBitte beachte: Es werden nur grundlegende Überprüfungen gegen bestehende Buchungen durchgeführt. Bitte prüfe, ob es keine Buchungskonflikte mit anderen Buchungen gibt. \n" -"

\n" -"\t\t\t\t" - -#: src/Wordpress/CustomPostType/Booking.php:773 +#: src/Wordpress/CustomPostType/Booking.php:786 msgid "Book full day" msgstr "Ganztägig buchen" -#: src/Wordpress/CustomPostType/Booking.php:776 +#: src/Wordpress/CustomPostType/Booking.php:789 msgid "The booking should apply to the entire day(s)" msgstr "Die Buchung soll auf den gesamten Tag / die gesamten Tage angewendet werden" -#: src/Wordpress/CustomPostType/Booking.php:816 +#: src/Wordpress/CustomPostType/Booking.php:829 msgid "Valid booking code will be automatically retrieved for bookings that apply to the full day." msgstr "Ein gültiger Buchungscode wird automatisch für Buchungen, die sich auf den ganzen Tag beziehen, generiert." -#: src/Wordpress/CustomPostType/Booking.php:825 +#: src/Wordpress/CustomPostType/Booking.php:838 msgid "" "Here you must select the user for whom the booking is made.
\n" " If the booking was made by a user via frontend booking process, the user will be shown in this field.\n" @@ -3934,7 +3914,7 @@ msgstr "" " Wenn die Buchung von einem/einer Nutzenden über den Frontend-Buchungsprozess vorgenommen wurde, wird der/die Nutzende in diesem Feld angezeigt.\n" "
Hinweis: Der/die Nutzende erhält eine Buchungsbestätigung, sobald die Buchung abgeschickt wurde." -#: src/Wordpress/CustomPostType/Booking.php:865 +#: src/Wordpress/CustomPostType/Booking.php:878 msgid "This will create the specified booking and send out the booking confirmation email." msgstr "Dadurch wird die angegebene Buchung erstellt und die Buchungsbestätigung per E-Mail verschickt." @@ -4006,11 +3986,11 @@ msgstr "Buchungen bei Totalausfall nicht stornieren" msgid "If checked, bookings will not be cancelled if the item has broken down. The user will be notified and once the item becomes available again, the old bookings are still valid." msgstr "Wenn ausgewählt, werden Buchungen nicht storniert, wenn ein Totalausfall für den Artikel gesetzt ist. Der / die Benutzer*in wird benachrichtigt und sobald der Artikel wieder verfügbar ist, sind die alten Buchungen weiterhin gültig." -#: src/Wordpress/CustomPostType/Item.php:353 +#: src/Wordpress/CustomPostType/Item.php:363 msgid "Add custom title for filter" msgstr "Benutzerdefinierten Titel für Filtergruppe hinzufügen" -#: src/Wordpress/CustomPostType/Item.php:356 +#: src/Wordpress/CustomPostType/Item.php:366 msgid "Define name that should be used for the category if it is displayed in the map as a filter group. You can also use this to add custom HTML to the category name. When left empty, the defined name of the category will be used." msgstr "Legt den Namen fest, der für die Kategorie verwendet werden soll, wenn sie in der Karte als Teil der Filtergruppe angezeigt wird. Hier kann auch benutzerdefinierter HTML-Code zum Kategorienamen hinzugefügt werden. Bleibt der Eintrag leer, wird der Standard Name der Kategorie verwendet." @@ -4292,7 +4272,7 @@ msgstr "Maximal %1$s Tage hintereinander buchbar." msgid "Bookings have to be made at least %1$s days in advance." msgstr "Buchungen müssen mindestens %1$s Tage im Voraus getätigt werden." -#: src/Wordpress/CustomPostType/Restriction.php:417 +#: src/Wordpress/CustomPostType/Restriction.php:399 msgid "" "Select the type of restriction.
\n" "\t\t\t\tSelect Notice, the item can still be used and if e.g. only one part is missing or defective.
\n" @@ -4408,23 +4388,6 @@ msgstr "Wenn diese Option ausgewählt ist, ist die API ohne API-Schlüssel zugä msgid "You can define on or more API shares. Read the documentation for more information about API shares and configuration %1$sAPI documentation%2$s" msgstr "Du kannst ein oder mehrere API-Freigaben definieren. Weitere Informationen zu API-Freigaben und zur Konfiguration findest du in der %1$sAPI-Dokumentation%2$s" -#: src/Wordpress/CustomPostType/Booking.php:888 -#, php-format -msgid "" -"Bookings should be created via frontend booking calendar.
\n" -"\t\tAs an admin you can create bookings via this admin interface. Please be aware that admin bookings are not validated\n" -"\t\tand checked. Use this function with care.
\n" -"\t\tClick on preview to show booking details in frontend
\n" -"\t\tTo search and filter bookings please integrate the frontend booking list via shortcode. \n" -"\t\tSee here %1$sHow to display the booking list%2$s" -msgstr "" -"Buchungen sollten über den Frontend-Buchungskalender erstellt werden.
\r\n" -"\t\tAls Admin kannst du über diese Admin-Oberfläche Buchungen anlegen. Bitte beachte, dass Admin-Buchungen nicht validiert\r\n" -"\t\tund überprüft werden. Verwende diese Funktion mit Vorsicht.
\r\n" -"\t\tKlicke auf Vorschau, um die Buchungsdetails im Frontend anzuzeigen.
\r\n" -"\t\tZur Suche und Filterung von Buchungen, binde bitte die Frontend-Buchungsliste per Shortcode ein. \r\n" -"\t\tMehr dazu %1$sBinde die Buchungsliste im Frontend ein.%2$s" - #: src/Wordpress/CustomPostType/Location.php:540 #, php-format msgid "If selected, all not selected days in any bookable timeframe that is connected to this location can be overbooked. Read the documentation %1$sCreate Locations%2$s for more information." @@ -4450,25 +4413,17 @@ msgstr "" "\t\t\t\t%1$sWeitere Informationen in der Dokumentation%2$s\r\n" "\t\t\t\t" -#: src/Model/Booking.php:1024 -#~ msgid "Unconfirmed" -#~ msgstr "Unbestätigt" - -#: src/Model/Booking.php:1022 -#~ msgid "Confirmed" -#~ msgstr "Bestätigt" - #: includes/OptionsArray.php:1553 msgid "Enables users to copy a url for a dynamic iCalendar feed into their own digital calendars." -msgstr "" +msgstr "Erlaubt Nutzenden eine URL für einen dynamischen iCalendar in ihre eigenen digitalen Kalender zu kopieren." #: includes/OptionsArray.php:1567 msgid "This is the event title that will be given to bookings that do not belong to the current user. This is what the CB-Manager will see when they subscribe to the station calendar. You can use template tags here as well" -msgstr "" +msgstr "Dies ist der Titel für Kalendereinträge von Buchungen, die nicht dem aktuell angemeldeten Nutzenden zugeordnet sind. Solche Einträge sind für Personen mit der Rolle „CB-Manager“ sichtbar, wenn sie den Kalender einer Station abonnieren. Hier können auch Template-Tags genutzt werden." #: includes/OptionsArray.php:1574 msgid "This is the event description that will be given to bookings that do not belong to the current user. This is what the CB-Manager will see when they subscribe to the station calendar. You can use template tags here." -msgstr "" +msgstr "Dies ist die Beschreibung für Kalendereinträge von Buchungen, die nicht dem aktuell angemeldeten Nutzenden zugeordnet sind. Solche Einträge sind für Personen mit der Rolle „CB-Manager“ sichtbar, wenn sie den Kalender einer Station abonnieren. Hier können auch Template-Tags genutzt werden." #: includes/OptionsArray.php:1576 msgid "" @@ -4478,3 +4433,65 @@ msgid "" "Booking code: {{booking:formattedBookingCode}}\n" "User Email: {{user:user_email}}" msgstr "" +"\n" +"Abholung: {{booking:pickupDatetime}}\r\n" +"Rückgabe: {{booking:returnDatetime}}\r\n" +"Buchungscode: {{booking:formattedBookingCode}}\r\n" +"E-Mail des Nutzenden: {{user:user_email}}" + +#: src/Wordpress/CustomPostType/Item.php:287 +msgid "Exclude from API" +msgstr "In API verstecken" + +#: src/Wordpress/CustomPostType/Item.php:288 +msgid "When this box is checked, the item will not appear in any of the API shares." +msgstr "Wenn diese Box angewählt ist taucht der Artikel in keiner der API Freigaben auf." + +#: src/Wordpress/CustomPostType/Booking.php:758 +msgid "" +"

Notice

In this view, you as an admin can create or modify existing bookings. Please use it with caution.
\n" +"\t\t\t\t

    \n" +"
  • Click on the preview button on the right panel to view more booking details and to cancel the booking via the cancel button.
  • \n" +"
  • Click on the Submit booking button at the end of the page to submit a new booking.
  • \n" +"
\n" +"\t\t\t\tPlease note: Only a few basic checks against existing bookings are performed. Please be wary of overlapping bookings.\n" +"

\n" +"\t\t\t\t" +msgstr "" +"

Achtung

In dieser Ansicht kannst du als Administrator*in Buchungen erstellen oder ändern. Bitte nutze die Möglichkeit mit Vorsicht.
\r\n" +"\t\t\t\t

    \r\n" +"
  • Klicke auf den Vorschau Knopf auf der rechten Seite, um weitere Buchungsdetails zu sehen und die Buchung über die Schaltfläche „Stornieren“ zu stornieren.
  • \r\n" +"
  • Klicke auf den Buchung abschicken Knopf am Ende der Seite um die Buchung zu bestätigen..
  • \r\n" +"
\r\n" +"\t\t\t\tBitte beachte:: Es werden nur grundlegende Überprüfungen gegen bestehende Buchungen durchgeführt. Bitte prüfe, ob es keine Buchungskonflikte mit anderen Buchungen gibt.\r\n" +"

\r\n" +"\t\t\t\t" + +#: src/Wordpress/CustomPostType/Booking.php:901 +#, php-format +msgid "" +"Bookings should be created via frontend booking calendar.
\n" +"\t\tAs an admin you can create bookings via this admin interface. Please be aware that admin bookings are not validated\n" +"\t\tand checked. Use this function with care.
\n" +"\t\tClick on preview to show booking details in frontend
\n" +"\t\tTo search and filter bookings please integrate the frontend booking list via shortcode.\n" +"\t\tSee here %1$sHow to display the booking list%2$s" +msgstr "" +"Buchungen sollten über den Buchungskalender im Frontend erstellt werden.
\r\n" +"\t\tAls Admin kannst du Buchungen über das Backend erstellen. Bitte beachte, dass die Buchungen dort nicht validiert werden.\r\n" +"\t\tNutze diese Funktion mit Vorsicht.
\r\n" +"\t\tKlicke auf den Vorschau Knopf, um die Details der Buchung im Frontend anzuzeigen.
\r\n" +"\t\tUm Buchungen zu filtern und durchsuchen, kann der Buchungsshortcode auf einer Frontend Seite eingefügt werden.\r\n" +"\t\tIn der Dokumentation %1$sBuchungsliste anzeigen%2$s" + +#: src/Wordpress/CustomPostType/Booking.php:304 +msgid "Invalid booking request. Please try again." +msgstr "Ungültige Buchungsanfrage. Bitte erneut versuchen." + +#: src/Model/Booking.php:1024 +#~ msgid "Unconfirmed" +#~ msgstr "Unbestätigt" + +#: src/Model/Booking.php:1022 +#~ msgid "Confirmed" +#~ msgstr "Bestätigt" diff --git a/languages/commonsbooking.pot b/languages/commonsbooking.pot index 1feb6de32..f4dc42332 100644 --- a/languages/commonsbooking.pot +++ b/languages/commonsbooking.pot @@ -2,14 +2,14 @@ # This file is distributed under the GPL v2 or later. msgid "" msgstr "" -"Project-Id-Version: Commons Booking 2.10.10\n" +"Project-Id-Version: Commons Booking 2.11\n" "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/commonsbooking\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"POT-Creation-Date: 2026-04-09T19:23:59+00:00\n" +"POT-Creation-Date: 2026-07-19T12:42:29+00:00\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "X-Generator: WP-CLI 2.12.0\n" "X-Domain: commonsbooking\n" @@ -596,8 +596,8 @@ msgid "The color used for dark text on light backgrounds" msgstr "" #: includes/OptionsArray.php:644 -#: src/Wordpress/CustomPostType/Restriction.php:305 -#: src/Wordpress/CustomPostType/Restriction.php:326 +#: src/Wordpress/CustomPostType/Restriction.php:287 +#: src/Wordpress/CustomPostType/Restriction.php:308 #: templates/dashboard-index.php:47 msgid "Restrictions" msgstr "" @@ -1025,7 +1025,7 @@ msgstr "" #: includes/OptionsArray.php:1321 #: src/Wordpress/CustomPostType/Map.php:557 #: src/Wordpress/CustomPostType/Restriction.php:47 -#: src/Wordpress/CustomPostType/Restriction.php:415 +#: src/Wordpress/CustomPostType/Restriction.php:397 #: src/Wordpress/CustomPostType/Timeframe.php:98 #: src/Wordpress/CustomPostType/Timeframe.php:455 msgid "Type" @@ -1299,71 +1299,71 @@ msgstr "" msgid "Every day" msgstr "" -#: src/CB/CB1UserFields.php:69 +#: src/CB/CB1UserFields.php:72 msgid "First Name" msgstr "" -#: src/CB/CB1UserFields.php:72 +#: src/CB/CB1UserFields.php:75 msgid "Please enter your first name" msgstr "" -#: src/CB/CB1UserFields.php:76 +#: src/CB/CB1UserFields.php:79 msgid "Last Name" msgstr "" -#: src/CB/CB1UserFields.php:79 +#: src/CB/CB1UserFields.php:82 msgid "Please enter your last name" msgstr "" -#: src/CB/CB1UserFields.php:83 +#: src/CB/CB1UserFields.php:86 msgid "Phone Number" msgstr "" -#: src/CB/CB1UserFields.php:86 +#: src/CB/CB1UserFields.php:89 msgid "Please enter your phone number" msgstr "" -#: src/CB/CB1UserFields.php:90 -#: src/CB/CB1UserFields.php:279 +#: src/CB/CB1UserFields.php:93 +#: src/CB/CB1UserFields.php:283 #: src/Wordpress/CustomPostType/Location.php:237 #: templates/booking-single.php:77 msgid "Address" msgstr "" -#: src/CB/CB1UserFields.php:93 +#: src/CB/CB1UserFields.php:96 msgid "Please enter your address" msgstr "" -#: src/CB/CB1UserFields.php:96 +#: src/CB/CB1UserFields.php:99 msgid "Terms and Conditions" msgstr "" -#: src/CB/CB1UserFields.php:99 +#: src/CB/CB1UserFields.php:102 msgid "I accept the terms & conditions" msgstr "" -#: src/CB/CB1UserFields.php:100 +#: src/CB/CB1UserFields.php:103 msgid "Please accept the terms & conditions" msgstr "" -#: src/CB/CB1UserFields.php:188 +#: src/CB/CB1UserFields.php:191 #, php-format msgid "Read the terms and services" msgstr "" -#: src/CB/CB1UserFields.php:267 +#: src/CB/CB1UserFields.php:271 msgid "Extra Fields" msgstr "" -#: src/CB/CB1UserFields.php:271 +#: src/CB/CB1UserFields.php:275 msgid "Phone number" msgstr "" -#: src/CB/CB1UserFields.php:287 +#: src/CB/CB1UserFields.php:291 msgid "Terms and conditions" msgstr "" -#: src/CB/CB1UserFields.php:297 +#: src/CB/CB1UserFields.php:301 msgid "Accepted Terms & Conditions" msgstr "" @@ -1476,7 +1476,7 @@ msgstr "" #. translators: %s = date in WordPress defined format #: src/Model/Booking.php:437 -#: src/Model/Timeframe.php:260 +#: src/Model/Timeframe.php:347 #, php-format msgid "on %s" msgstr "" @@ -1484,7 +1484,7 @@ msgstr "" #. translators: %1 = startdate, %2 = enddate in WordPress defined format #. translators: %1$s = startdate, second %2$s = enddate in WordPress defined format #: src/Model/Booking.php:440 -#: src/Model/Timeframe.php:275 +#: src/Model/Timeframe.php:352 #, php-format msgid "from %1$s until %2$s" msgstr "" @@ -1559,93 +1559,93 @@ msgstr "" msgid "Please contact the contact persons at the location directly if you have any questions regarding collection or return:" msgstr "" -#: src/Model/Restriction.php:244 -#: src/Model/Restriction.php:268 +#: src/Model/Restriction.php:248 +#: src/Model/Restriction.php:275 msgid "Not set" msgstr "" -#: src/Model/Timeframe.php:255 +#: src/Model/Timeframe.php:331 msgid "Available here" msgstr "" #. translators: %s = date in WordPress defined format -#: src/Model/Timeframe.php:265 +#: src/Model/Timeframe.php:339 #, php-format msgid "from %s" msgstr "" -#: src/Model/Timeframe.php:269 +#: src/Model/Timeframe.php:343 msgid "permanently" msgstr "" #. translators: %s = enddate in WordPress defined format -#: src/Model/Timeframe.php:282 +#: src/Model/Timeframe.php:359 #, php-format msgid "until %s" msgstr "" -#: src/Model/Timeframe.php:555 +#: src/Model/Timeframe.php:632 msgid "Could not get item or location. Please set a valid item and location." msgstr "" -#: src/Model/Timeframe.php:564 +#: src/Model/Timeframe.php:641 msgid "Item or location is missing. Please set item and location." msgstr "" -#: src/Model/Timeframe.php:577 +#: src/Model/Timeframe.php:654 msgid "No dates selected. Please select at least one date." msgstr "" -#: src/Model/Timeframe.php:587 +#: src/Model/Timeframe.php:664 msgid "The same date was selected multiple times. Please select each date only once." msgstr "" -#: src/Model/Timeframe.php:596 +#: src/Model/Timeframe.php:673 msgid "Startdate is missing. Please enter a start date to publish this timeframe." msgstr "" -#: src/Model/Timeframe.php:610 +#: src/Model/Timeframe.php:687 msgid "A pickup time but no return time has been set. Please set the return time." msgstr "" -#: src/Model/Timeframe.php:620 +#: src/Model/Timeframe.php:697 msgid "End date is before start date. Please set a valid end date." msgstr "" -#: src/Model/Timeframe.php:630 +#: src/Model/Timeframe.php:707 msgid "The start- and end-time of the timeframe can not be the same. Please check the full-day checkbox if you want users to be able to book the full day." msgstr "" #. translators: %1$s = timeframe-ID, %2$s is timeframe post_title -#: src/Model/Timeframe.php:655 +#: src/Model/Timeframe.php:732 #, php-format msgid "Item is already bookable at another location within the same date range. See other timeframe ID: %1$s: %2$s" msgstr "" #. translators: first %s = timeframe-ID, second %s is timeframe post_title -#: src/Model/Timeframe.php:691 +#: src/Model/Timeframe.php:768 #, php-format msgid "See overlapping timeframe ID: %1$s %2$s" msgstr "" -#: src/Model/Timeframe.php:790 +#: src/Model/Timeframe.php:867 msgid "Overlapping bookable timeframes are only allowed to have the same grid." msgstr "" -#: src/Model/Timeframe.php:806 +#: src/Model/Timeframe.php:883 msgid "Daily repeated time periods are not allowed to overlap." msgstr "" -#: src/Model/Timeframe.php:820 +#: src/Model/Timeframe.php:897 msgid "Overlapping bookable timeframes are not allowed to have the same weekdays." msgstr "" -#: src/Model/Timeframe.php:832 +#: src/Model/Timeframe.php:909 msgid "Overlapping bookable timeframes are not allowed to have the same dates." msgstr "" -#: src/Model/Timeframe.php:839 -#: src/Model/Timeframe.php:846 +#: src/Model/Timeframe.php:916 +#: src/Model/Timeframe.php:923 msgid "The other timeframe is overlapping with your weekly configuration." msgstr "" @@ -1666,7 +1666,7 @@ msgstr "" #: src/Plugin.php:720 #: src/Plugin.php:735 -#: src/Wordpress/CustomPostType/Booking.php:936 +#: src/Wordpress/CustomPostType/Booking.php:949 msgid "CommonsBooking Bookings" msgstr "" @@ -1992,15 +1992,15 @@ msgid "" msgstr "" #: src/View/Admin/Filter.php:58 -#: src/Wordpress/CustomPostType/Booking.php:779 -#: src/Wordpress/CustomPostType/Restriction.php:451 +#: src/Wordpress/CustomPostType/Booking.php:792 +#: src/Wordpress/CustomPostType/Restriction.php:433 #: src/Wordpress/CustomPostType/Timeframe.php:678 msgid "Start date" msgstr "" #: src/View/Admin/Filter.php:62 -#: src/Wordpress/CustomPostType/Booking.php:796 -#: src/Wordpress/CustomPostType/Restriction.php:461 +#: src/Wordpress/CustomPostType/Booking.php:809 +#: src/Wordpress/CustomPostType/Restriction.php:443 #: src/Wordpress/CustomPostType/Timeframe.php:702 msgid "End date" msgstr "" @@ -2024,7 +2024,7 @@ msgstr "" #: src/View/Booking.php:196 #: src/View/MassOperations.php:38 -#: src/Wordpress/CustomPostType/Booking.php:446 +#: src/Wordpress/CustomPostType/Booking.php:459 #: src/Wordpress/CustomPostType/Timeframe.php:97 #: templates/shortcode-bookings.php:74 msgid "User" @@ -2032,8 +2032,8 @@ msgstr "" #: src/View/Booking.php:200 #: src/View/MassOperations.php:42 -#: src/Wordpress/CustomPostType/Booking.php:973 -#: src/Wordpress/CustomPostType/Restriction.php:477 +#: src/Wordpress/CustomPostType/Booking.php:986 +#: src/Wordpress/CustomPostType/Restriction.php:459 msgid "Status" msgstr "" @@ -2041,8 +2041,8 @@ msgstr "" msgid "Code" msgstr "" -#: src/View/Booking.php:581 -#: src/Wordpress/CustomPostType/Booking.php:864 +#: src/View/Booking.php:578 +#: src/Wordpress/CustomPostType/Booking.php:877 msgid "Submit booking" msgstr "" @@ -2135,37 +2135,37 @@ msgstr "" msgid "Error sending booking codes" msgstr "" -#: src/View/BookingCodes.php:556 +#: src/View/BookingCodes.php:555 msgid "An unknown error occured" msgstr "" -#: src/View/BookingCodes.php:557 +#: src/View/BookingCodes.php:556 msgid "Email booking codes" msgstr "" -#: src/View/Calendar.php:177 +#: src/View/Calendar.php:181 msgid "No items found." msgstr "" -#: src/View/Calendar.php:233 -#: src/Wordpress/CustomPostType/Booking.php:447 -#: src/Wordpress/CustomPostType/Booking.php:761 -#: src/Wordpress/CustomPostType/Booking.php:989 +#: src/View/Calendar.php:237 +#: src/Wordpress/CustomPostType/Booking.php:460 +#: src/Wordpress/CustomPostType/Booking.php:774 +#: src/Wordpress/CustomPostType/Booking.php:1002 #: src/Wordpress/CustomPostType/Item.php:117 #: src/Wordpress/CustomPostType/Restriction.php:48 -#: src/Wordpress/CustomPostType/Restriction.php:438 +#: src/Wordpress/CustomPostType/Restriction.php:420 #: src/Wordpress/CustomPostType/Timeframe.php:99 #: templates/shortcode-bookings.php:73 msgid "Item" msgstr "" -#: src/View/Calendar.php:234 -#: src/Wordpress/CustomPostType/Booking.php:448 -#: src/Wordpress/CustomPostType/Booking.php:767 -#: src/Wordpress/CustomPostType/Booking.php:985 +#: src/View/Calendar.php:238 +#: src/Wordpress/CustomPostType/Booking.php:461 +#: src/Wordpress/CustomPostType/Booking.php:780 +#: src/Wordpress/CustomPostType/Booking.php:998 #: src/Wordpress/CustomPostType/Location.php:139 #: src/Wordpress/CustomPostType/Restriction.php:49 -#: src/Wordpress/CustomPostType/Restriction.php:431 +#: src/Wordpress/CustomPostType/Restriction.php:413 #: src/Wordpress/CustomPostType/Timeframe.php:100 #: src/Wordpress/CustomPostType/Timeframe.php:463 #: templates/shortcode-bookings.php:75 @@ -2362,150 +2362,154 @@ msgid "Your reservation has expired, please try to book again" msgstr "" #: src/Wordpress/CustomPostType/Booking.php:291 -#: src/Wordpress/CustomPostType/Booking.php:323 +#: src/Wordpress/CustomPostType/Booking.php:336 msgid "There is already a booking in this time-range. This notice may also appear if there is an unconfirmed booking in the requested period. Unconfirmed bookings are deleted after about 10 minutes. Please try again in a few minutes." msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:307 +#: src/Wordpress/CustomPostType/Booking.php:304 +msgid "Invalid booking request. Please try again." +msgstr "" + +#: src/Wordpress/CustomPostType/Booking.php:320 msgid "Booking canceled." msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:331 -#: src/Wordpress/CustomPostType/Booking.php:524 -#: src/Wordpress/CustomPostType/Booking.php:712 +#: src/Wordpress/CustomPostType/Booking.php:344 +#: src/Wordpress/CustomPostType/Booking.php:537 +#: src/Wordpress/CustomPostType/Booking.php:725 #: src/Wordpress/CustomPostType/Timeframe.php:132 msgid "Booking" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:375 +#: src/Wordpress/CustomPostType/Booking.php:388 msgid "There was an error while saving the booking. Please try again. Thrown error:" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:392 +#: src/Wordpress/CustomPostType/Booking.php:405 msgid "There was an error while saving the booking. Please try again. Resulting WP_ERROR: " msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:449 +#: src/Wordpress/CustomPostType/Booking.php:462 msgid "Bookingdate" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:450 +#: src/Wordpress/CustomPostType/Booking.php:463 #: src/Wordpress/CustomPostType/Restriction.php:50 #: src/Wordpress/CustomPostType/Timeframe.php:101 #: src/Wordpress/CustomPostType/Timeframe.php:758 msgid "Start Date" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:451 +#: src/Wordpress/CustomPostType/Booking.php:464 #: src/Wordpress/CustomPostType/Restriction.php:51 #: src/Wordpress/CustomPostType/Timeframe.php:102 msgid "End Date" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:452 +#: src/Wordpress/CustomPostType/Booking.php:465 msgid "Booking Status" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:453 -#: src/Wordpress/CustomPostType/Booking.php:981 +#: src/Wordpress/CustomPostType/Booking.php:466 +#: src/Wordpress/CustomPostType/Booking.php:994 #: src/Wordpress/CustomPostType/Timeframe.php:448 msgid "Comment" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:523 +#: src/Wordpress/CustomPostType/Booking.php:536 #: templates/dashboard-index.php:45 msgid "Bookings" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:525 +#: src/Wordpress/CustomPostType/Booking.php:538 #: src/Wordpress/CustomPostType/Item.php:118 #: src/Wordpress/CustomPostType/Location.php:140 -#: src/Wordpress/CustomPostType/Restriction.php:307 -#: src/Wordpress/CustomPostType/Timeframe.php:1152 +#: src/Wordpress/CustomPostType/Restriction.php:289 +#: src/Wordpress/CustomPostType/Timeframe.php:1153 msgid "Add new" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:526 -#: src/Wordpress/CustomPostType/Booking.php:528 +#: src/Wordpress/CustomPostType/Booking.php:539 +#: src/Wordpress/CustomPostType/Booking.php:541 msgid "Add new booking" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:527 -#: src/Wordpress/CustomPostType/Booking.php:743 +#: src/Wordpress/CustomPostType/Booking.php:540 +#: src/Wordpress/CustomPostType/Booking.php:756 msgid "Edit booking" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:529 +#: src/Wordpress/CustomPostType/Booking.php:542 msgid "Show booking" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:530 +#: src/Wordpress/CustomPostType/Booking.php:543 msgid "Show bookings" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:531 +#: src/Wordpress/CustomPostType/Booking.php:544 msgid "Search bookings" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:532 +#: src/Wordpress/CustomPostType/Booking.php:545 msgid "Bookings not found" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:533 +#: src/Wordpress/CustomPostType/Booking.php:546 msgid "No bookings found in trash" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:534 +#: src/Wordpress/CustomPostType/Booking.php:547 msgid "Parent bookings:" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:535 +#: src/Wordpress/CustomPostType/Booking.php:548 msgid "All bookings" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:536 -#: src/Wordpress/CustomPostType/Timeframe.php:1163 +#: src/Wordpress/CustomPostType/Booking.php:549 +#: src/Wordpress/CustomPostType/Timeframe.php:1164 msgid "Timeframe archive" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:537 -#: src/Wordpress/CustomPostType/Timeframe.php:1164 +#: src/Wordpress/CustomPostType/Booking.php:550 +#: src/Wordpress/CustomPostType/Timeframe.php:1165 msgid "Timeframe attributes" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:538 +#: src/Wordpress/CustomPostType/Booking.php:551 msgid "Add to booking" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:539 +#: src/Wordpress/CustomPostType/Booking.php:552 msgid "Added to booking" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:540 -#: src/Wordpress/CustomPostType/Timeframe.php:1167 +#: src/Wordpress/CustomPostType/Booking.php:553 +#: src/Wordpress/CustomPostType/Timeframe.php:1168 msgid "Timeframe image" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:541 +#: src/Wordpress/CustomPostType/Booking.php:554 msgid "set booking image" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:542 +#: src/Wordpress/CustomPostType/Booking.php:555 msgid "remove booking image" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:543 +#: src/Wordpress/CustomPostType/Booking.php:556 msgid "use as booking image" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:544 -#: src/Wordpress/CustomPostType/Timeframe.php:1150 -#: src/Wordpress/CustomPostType/Timeframe.php:1171 +#: src/Wordpress/CustomPostType/Booking.php:557 +#: src/Wordpress/CustomPostType/Timeframe.php:1151 +#: src/Wordpress/CustomPostType/Timeframe.php:1172 #: templates/dashboard-index.php:37 msgid "Timeframes" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:745 +#: src/Wordpress/CustomPostType/Booking.php:758 msgid "" "

Notice

In this view, you as an admin can create or modify existing bookings. Please use it with caution.
\n" "\t\t\t\t

    \n" @@ -2513,107 +2517,107 @@ msgid "" "
  • Click on the Submit booking button at the end of the page to submit a new booking.
  • \n" "
\n" "\t\t\t\tPlease note: Only a few basic checks against existing bookings are performed. Please be wary of overlapping bookings.\n" -"

\n" +"

\n" "\t\t\t\t" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:773 +#: src/Wordpress/CustomPostType/Booking.php:786 msgid "Book full day" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:776 +#: src/Wordpress/CustomPostType/Booking.php:789 msgid "The booking should apply to the entire day(s)" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:780 +#: src/Wordpress/CustomPostType/Booking.php:793 msgid "Set the start date. You must set the time to 00:00 if you want to book the full day " msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:797 +#: src/Wordpress/CustomPostType/Booking.php:810 msgid "Set the end date. You must set time to 23:59 if you want to book the full day" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:813 +#: src/Wordpress/CustomPostType/Booking.php:826 #: templates/booking-single.php:59 msgid "Booking Code" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:816 +#: src/Wordpress/CustomPostType/Booking.php:829 msgid "Valid booking code will be automatically retrieved for bookings that apply to the full day." msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:819 +#: src/Wordpress/CustomPostType/Booking.php:832 msgid "Booking User" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:825 +#: src/Wordpress/CustomPostType/Booking.php:838 msgid "" "Here you must select the user for whom the booking is made.
\n" " If the booking was made by a user via frontend booking process, the user will be shown in this field.\n" "
Notice:The user will receive a booking confirmation as soon as the booking is submitted." msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:834 +#: src/Wordpress/CustomPostType/Booking.php:847 msgid "Admin Booking User" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:845 +#: src/Wordpress/CustomPostType/Booking.php:858 msgid "This is the admin user who created or modified this booking." msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:852 +#: src/Wordpress/CustomPostType/Booking.php:865 msgid "External comment" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:853 +#: src/Wordpress/CustomPostType/Booking.php:866 msgid "This comment can be seen by users in booking details. It can be set by users during the booking confirmation process if comments are enabled in settings." msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:858 +#: src/Wordpress/CustomPostType/Booking.php:871 #: templates/booking-single.php:131 msgid "Internal comment" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:859 +#: src/Wordpress/CustomPostType/Booking.php:872 msgid "This internal comment can only be seen in the backend by privileged users like admins or cb-managers" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:865 +#: src/Wordpress/CustomPostType/Booking.php:878 msgid "This will create the specified booking and send out the booking confirmation email." msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:888 +#: src/Wordpress/CustomPostType/Booking.php:901 #, php-format msgid "" "Bookings should be created via frontend booking calendar.
\n" "\t\tAs an admin you can create bookings via this admin interface. Please be aware that admin bookings are not validated\n" "\t\tand checked. Use this function with care.
\n" "\t\tClick on preview to show booking details in frontend
\n" -"\t\tTo search and filter bookings please integrate the frontend booking list via shortcode. \n" +"\t\tTo search and filter bookings please integrate the frontend booking list via shortcode.\n" "\t\tSee here %1$sHow to display the booking list%2$s" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:961 +#: src/Wordpress/CustomPostType/Booking.php:974 msgid "Booking start" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:965 +#: src/Wordpress/CustomPostType/Booking.php:978 msgid "Booking end" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:969 +#: src/Wordpress/CustomPostType/Booking.php:982 msgid "Time of booking" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:977 +#: src/Wordpress/CustomPostType/Booking.php:990 msgid "Booking code" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:993 +#: src/Wordpress/CustomPostType/Booking.php:1006 msgid "Time of cancellation" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:997 +#: src/Wordpress/CustomPostType/Booking.php:1010 msgid "Admin booking by" msgstr "" @@ -2720,20 +2724,28 @@ msgstr "" msgid "Email addresses to which notifications about a change of item status (restriction, breakdown) shall be sent. You can enter multiple addresses separated by commas." msgstr "" -#: src/Wordpress/CustomPostType/Item.php:293 +#: src/Wordpress/CustomPostType/Item.php:287 +msgid "Exclude from API" +msgstr "" + +#: src/Wordpress/CustomPostType/Item.php:288 +msgid "When this box is checked, the item will not appear in any of the API shares." +msgstr "" + +#: src/Wordpress/CustomPostType/Item.php:303 msgid "Item Meta-Data" msgstr "" -#: src/Wordpress/CustomPostType/Item.php:324 -#: src/Wordpress/CustomPostType/Item.php:344 +#: src/Wordpress/CustomPostType/Item.php:334 +#: src/Wordpress/CustomPostType/Item.php:354 msgid "Item Category" msgstr "" -#: src/Wordpress/CustomPostType/Item.php:353 +#: src/Wordpress/CustomPostType/Item.php:363 msgid "Add custom title for filter" msgstr "" -#: src/Wordpress/CustomPostType/Item.php:356 +#: src/Wordpress/CustomPostType/Item.php:366 msgid "Define name that should be used for the category if it is displayed in the map as a filter group. You can also use this to add custom HTML to the category name. When left empty, the defined name of the category will be used." msgstr "" @@ -3474,81 +3486,81 @@ msgstr "" msgid "Filter By Status " msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:306 -#: src/Wordpress/CustomPostType/Restriction.php:387 +#: src/Wordpress/CustomPostType/Restriction.php:288 +#: src/Wordpress/CustomPostType/Restriction.php:369 msgid "Restriction" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:308 -#: src/Wordpress/CustomPostType/Restriction.php:310 +#: src/Wordpress/CustomPostType/Restriction.php:290 +#: src/Wordpress/CustomPostType/Restriction.php:292 msgid "Add new Restriction" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:309 +#: src/Wordpress/CustomPostType/Restriction.php:291 msgid "Edit Restriction" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:311 +#: src/Wordpress/CustomPostType/Restriction.php:293 msgid "Show Restriction" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:312 +#: src/Wordpress/CustomPostType/Restriction.php:294 msgid "Show Restrictions" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:313 +#: src/Wordpress/CustomPostType/Restriction.php:295 msgid "Search Restrictions" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:314 +#: src/Wordpress/CustomPostType/Restriction.php:296 msgid "Restrictions not found" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:315 +#: src/Wordpress/CustomPostType/Restriction.php:297 msgid "No Restrictions found in trash" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:316 +#: src/Wordpress/CustomPostType/Restriction.php:298 msgid "Parent Restrictions:" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:317 +#: src/Wordpress/CustomPostType/Restriction.php:299 msgid "All Restrictions" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:318 +#: src/Wordpress/CustomPostType/Restriction.php:300 msgid "Restriction archive" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:319 +#: src/Wordpress/CustomPostType/Restriction.php:301 msgid "Restriction attributes" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:320 +#: src/Wordpress/CustomPostType/Restriction.php:302 msgid "Add to Restriction" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:321 +#: src/Wordpress/CustomPostType/Restriction.php:303 msgid "Added to Restriction" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:322 +#: src/Wordpress/CustomPostType/Restriction.php:304 msgid "Restriction image" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:323 +#: src/Wordpress/CustomPostType/Restriction.php:305 msgid "set Restriction image" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:324 +#: src/Wordpress/CustomPostType/Restriction.php:306 msgid "remove Restriction image" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:325 +#: src/Wordpress/CustomPostType/Restriction.php:307 msgid "use as Restriction image" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:417 +#: src/Wordpress/CustomPostType/Restriction.php:399 msgid "" "Select the type of restriction.
\n" "\t\t\t\tSelect Notice, the item can still be used and if e.g. only one part is missing or defective.
\n" @@ -3557,30 +3569,30 @@ msgid "" "\t\t\t\t" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:434 -#: src/Wordpress/CustomPostType/Restriction.php:441 +#: src/Wordpress/CustomPostType/Restriction.php:416 +#: src/Wordpress/CustomPostType/Restriction.php:423 #: src/Wordpress/CustomPostType/Timeframe.php:815 #: templates/shortcode-bookings.php:55 msgid "All" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:445 +#: src/Wordpress/CustomPostType/Restriction.php:427 msgid "Hint" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:447 +#: src/Wordpress/CustomPostType/Restriction.php:429 msgid "Please enter here a short information about the reason and possible effects of the usage restriction.
The explanation will be displayed on the article page and in the notification e-mail." msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:452 +#: src/Wordpress/CustomPostType/Restriction.php:434 msgid "Set the start date and time" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:462 +#: src/Wordpress/CustomPostType/Restriction.php:444 msgid "Set the estimated end date and time" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:480 +#: src/Wordpress/CustomPostType/Restriction.php:462 msgid "" "Choose status of this restriction.
\n" "\t\t\t\tSet to None if you want to deactivate the restriction.
\n" @@ -3590,31 +3602,31 @@ msgid "" "Select the desired status and then click the \"Send\" button to send the e-mail.
" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:495 +#: src/Wordpress/CustomPostType/Restriction.php:477 msgid "Send notification emails to users" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:496 +#: src/Wordpress/CustomPostType/Restriction.php:478 msgid "Important: Please save this restriction before clicking the send-button. Dependent of the status of the restriction, the appropriate notifications are sent to all affected users and location admins. You can configure the e-mail templates via Options -> Commonsbooking -> Tab Restrictions" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:514 +#: src/Wordpress/CustomPostType/Restriction.php:496 msgid "Total breakdown" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:515 +#: src/Wordpress/CustomPostType/Restriction.php:497 msgid "Notice" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:525 +#: src/Wordpress/CustomPostType/Restriction.php:507 msgid "Not active" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:526 +#: src/Wordpress/CustomPostType/Restriction.php:508 msgid "Active" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:527 +#: src/Wordpress/CustomPostType/Restriction.php:509 msgid "Problem solved" msgstr "" @@ -3643,7 +3655,7 @@ msgid "Select Dates:" msgstr "" #: src/Wordpress/CustomPostType/Timeframe.php:420 -#: src/Wordpress/CustomPostType/Timeframe.php:1151 +#: src/Wordpress/CustomPostType/Timeframe.php:1152 msgid "Timeframe" msgstr "" @@ -3928,60 +3940,60 @@ msgstr "" msgid "Orphaned bookings found, can migrate. Click here to migrate " msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1153 -#: src/Wordpress/CustomPostType/Timeframe.php:1155 +#: src/Wordpress/CustomPostType/Timeframe.php:1154 +#: src/Wordpress/CustomPostType/Timeframe.php:1156 msgid "Add new timeframe" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1154 +#: src/Wordpress/CustomPostType/Timeframe.php:1155 msgid "Edit timeframe" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1156 +#: src/Wordpress/CustomPostType/Timeframe.php:1157 msgid "Show timeframe" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1157 +#: src/Wordpress/CustomPostType/Timeframe.php:1158 msgid "Show timeframes" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1158 +#: src/Wordpress/CustomPostType/Timeframe.php:1159 msgid "Search timeframes" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1159 +#: src/Wordpress/CustomPostType/Timeframe.php:1160 msgid "Timeframes not found" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1160 +#: src/Wordpress/CustomPostType/Timeframe.php:1161 msgid "No timeframes found in trash" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1161 +#: src/Wordpress/CustomPostType/Timeframe.php:1162 msgid "Parent timeframes:" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1162 +#: src/Wordpress/CustomPostType/Timeframe.php:1163 msgid "All timeframes" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1165 +#: src/Wordpress/CustomPostType/Timeframe.php:1166 msgid "Add to timeframe" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1166 +#: src/Wordpress/CustomPostType/Timeframe.php:1167 msgid "Added to timeframe" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1168 +#: src/Wordpress/CustomPostType/Timeframe.php:1169 msgid "set timeframe image" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1169 +#: src/Wordpress/CustomPostType/Timeframe.php:1170 msgid "remove timeframe image" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1170 +#: src/Wordpress/CustomPostType/Timeframe.php:1171 msgid "use as timeframe image" msgstr "" diff --git a/package-lock.json b/package-lock.json index 3433b16f0..1c5d199dc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "commonsbooking", - "version": "2.10.10", + "version": "2.11", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "commonsbooking", - "version": "2.10.10", + "version": "2.11", "license": "SEE LICENSE IN LICENSE.txt", "dependencies": { "@commonsbooking/frontend": "^0.1.0-beta.7", @@ -17,18 +17,18 @@ "leaflet.markercluster": "^1.5.0", "moment": "^2.19.4", "search-insights": "^2.17.3", - "select2": "^4.0.13", + "select2": "^4.1.0", "shufflejs": "^6.1.1", "spin.js": "^2.3.2", - "vue": "^3.5.30" + "vue": "^3.5.40" }, "devDependencies": { - "@babel/preset-env": "^7.29.2", - "@wordpress/env": "^11.0.0", + "@babel/preset-env": "^7.29.7", + "@wordpress/env": "^11.11.0", "commons-api": "git+https://github.com/wielebenwir/commons-api.git", - "cypress": "^15.13.1", + "cypress": "^15.18.1", "editorconfig": "^3.0.2", - "grunt": "^1.6.1", + "grunt": "^1.6.2", "grunt-babel": "^8.0.0", "grunt-cli": "^1.5.0", "grunt-contrib-clean": "^2.0.1", @@ -41,8 +41,8 @@ "grunt-dart-sass": "^2.0.1", "matchdep": "^2.0.0", "medium-zoom": "^1.1.0", - "prettier": "^3.3.3", - "sass": "^1.97.3", + "prettier": "^3.9.5", + "sass": "^1.101.0", "vitepress": "^1.6.4" } }, @@ -285,13 +285,13 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", - "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.28.5", + "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -300,9 +300,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", - "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", "dev": true, "license": "MIT", "engines": { @@ -346,14 +346,14 @@ "dev": true }, "node_modules/@babel/generator": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz", - "integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.0", - "@babel/types": "^7.29.0", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -363,27 +363,27 @@ } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", - "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz", + "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.27.3" + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", - "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.28.6", - "@babel/helper-validator-option": "^7.27.1", + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -393,18 +393,18 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.6.tgz", - "integrity": "sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.7.tgz", + "integrity": "sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-member-expression-to-functions": "^7.28.5", - "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/helper-replace-supers": "^7.28.6", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/traverse": "^7.28.6", + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/traverse": "^7.29.7", "semver": "^6.3.1" }, "engines": { @@ -415,13 +415,13 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.28.5.tgz", - "integrity": "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.29.7.tgz", + "integrity": "sha512-907Uymvqgg1dwUA+7IGwFAOSYzQOuzPXKNJ1yxzwPffzkYFg2q2eHi1fIOs6sXkG9NbIUMunnUlkYsfRFNvomg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-annotate-as-pure": "^7.29.7", "regexpu-core": "^6.3.1", "semver": "^6.3.1" }, @@ -450,9 +450,9 @@ } }, "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", "dev": true, "license": "MIT", "engines": { @@ -460,43 +460,43 @@ } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", - "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz", + "integrity": "sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.28.5", - "@babel/types": "^7.28.5" + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", - "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", - "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.28.6", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.6" + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -506,22 +506,22 @@ } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", - "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz", + "integrity": "sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.27.1" + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", - "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", "dev": true, "license": "MIT", "engines": { @@ -529,15 +529,15 @@ } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", - "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.29.7.tgz", + "integrity": "sha512-16AMiW26DbXWBbr3B8wNozKM0ydMLB892vaOaJW/fPJdnT8vJk5sdkQcU/isqUxyCE0cEoa8wZOcbgDuC4b6Og==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-wrap-function": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-wrap-function": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -547,15 +547,15 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.28.6.tgz", - "integrity": "sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz", + "integrity": "sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.28.5", - "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/traverse": "^7.28.6" + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -565,41 +565,41 @@ } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", - "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz", + "integrity": "sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", "dev": true, "license": "MIT", "engines": { @@ -607,15 +607,15 @@ } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.6.tgz", - "integrity": "sha512-z+PwLziMNBeSQJonizz2AGnndLsP2DeGHIxDAn+wdHOGuo4Fo1x1HBPPXeE9TAOPHNNWQKCSlA2VZyYyyibDnQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.29.7.tgz", + "integrity": "sha512-iES0Skag9ERIF68aXadpO6dbXa03mNWK3sEqJaMnLNs/eC3l0lkImdfoy6Y09/SfkpawdAB4RjQ7PVA7TcVGdw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -636,12 +636,12 @@ } }, "node_modules/@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", "license": "MIT", "dependencies": { - "@babel/types": "^7.29.0" + "@babel/types": "^7.29.7" }, "bin": { "parser": "bin/babel-parser.js" @@ -651,14 +651,14 @@ } }, "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz", - "integrity": "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.29.7.tgz", + "integrity": "sha512-j8SrR0zLZrRsC09DlszEx8FpMiwukKffYXMK0d5LmOglO7vGG6sz/BR/20yHqWH+Lnn31JTt2PE3hIWNgM2J6w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.5" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -668,13 +668,13 @@ } }, "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", - "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.29.7.tgz", + "integrity": "sha512-r8j8escF+U2FUHo0KOhPUdMzUO+jp9fInva6+ACVAF3Y97Ev+5iNZwiqTghmzNeWwDkOPlYuTcfb1vDaoZKmAQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -684,13 +684,30 @@ } }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", - "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.29.7.tgz", + "integrity": "sha512-GE1TFSiuFeGsCxmYXZl8HwoPrVlwe4rHPFE8weieGKZqnDORK+Ar3vgWMgW+AOxQ6/2TgLSKx9p6W7O4rC6qgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array/-/plugin-bugfix-safari-rest-destructuring-rhs-array-7.29.7.tgz", + "integrity": "sha512-oBNVCvnO5tND+xSopWvV8WNGfpTfgP4Zr/YXXSj8zfmcPktp5Ku/aZlsIowgSD4fjmgHn6sGmB9APVsU5zOdhA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -700,15 +717,15 @@ } }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", - "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.29.7.tgz", + "integrity": "sha512-QQt9qKHZ2sg/kivaLr7lnQr8HVrQDdBNSfCsTjiDxRuX/K5ORyKq+Bu8Xr0cDE3Dfkv0cw28Ve0EKyKMvulkOw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/plugin-transform-optional-chaining": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/plugin-transform-optional-chaining": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -718,14 +735,14 @@ } }, "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.6.tgz", - "integrity": "sha512-a0aBScVTlNaiUe35UtfxAN7A/tehvvG4/ByO6+46VPKTRSlfnAFsgKy0FUh+qAkQrDTmhDkT+IBOKlOoMUxQ0g==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.29.7.tgz", + "integrity": "sha512-pn6QacGLgvCcwc+syUhKE/qSjV2D1IHDB84RNxWYSt1mW3K/SCtjinZ2p0cETJxAWBjPy3K/1lHwG5BjjPxNlw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/traverse": "^7.28.6" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -747,13 +764,13 @@ } }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.28.6.tgz", - "integrity": "sha512-pSJUpFHdx9z5nqTSirOCMtYVP2wFgoWhP0p3g8ONK/4IHhLIBd0B9NYqAvIUAhq+OkhO4VM1tENCt0cjlsNShw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.29.7.tgz", + "integrity": "sha512-/An1OCBN93thpBAGyfsK2pcf0jvju1SAtKkL2Ny++B5Sy6sqgzXDQH1cZxWbF96Wuk+bn41MDA9bLd4VVAw6rw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -763,13 +780,13 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", - "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.29.7.tgz", + "integrity": "sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -795,13 +812,13 @@ } }, "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", - "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.29.7.tgz", + "integrity": "sha512-N7zArUXWzAMzm+/N0uPBeVB3Fam5lMxtUwMmDK5f/IBBS7a7p1qeUoxd/6CckXoxUdgsntq1Dh8xNW06maZbDQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -811,15 +828,15 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.0.tgz", - "integrity": "sha512-va0VdWro4zlBr2JsXC+ofCPB2iG12wPtVGTWFx2WLDOM3nYQZZIGP82qku2eW/JR83sD+k2k+CsNtyEbUqhU6w==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.7.tgz", + "integrity": "sha512-d98gXZkgswvkyohMBABkhm3GeXhYj8psWfwQ2C7gtfrKGTykQa/iOIi+JJhwMjPlZ6Vm2XN+DCf3Es1EoG4ZLA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/helper-remap-async-to-generator": "^7.27.1", - "@babel/traverse": "^7.29.0" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-remap-async-to-generator": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -829,15 +846,15 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.28.6.tgz", - "integrity": "sha512-ilTRcmbuXjsMmcZ3HASTe4caH5Tpo93PkTxF9oG2VZsSWsahydmcEHhix9Ik122RcTnZnUzPbmux4wh1swfv7g==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.29.7.tgz", + "integrity": "sha512-pcUb2SS+RMo9TWVBwKGI5ShtoG7R+zBsFmCKDa6fe8c+hPr3XJlZgoE5j6i8W7gDjhyvy+85vmYexanvXh3d1w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/helper-remap-async-to-generator": "^7.27.1" + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-remap-async-to-generator": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -847,13 +864,13 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", - "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.29.7.tgz", + "integrity": "sha512-cUSmjh72N+rN4PrkFlN1dJwNCwjVp5d38/CQrEsFggkD10UiFlBFgdH3tv5dNsLuHY+3S8db2xCHjhZcv5WgvA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -863,13 +880,13 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.6.tgz", - "integrity": "sha512-tt/7wOtBmwHPNMPu7ax4pdPz6shjFrmHDghvNC+FG9Qvj7D6mJcoRQIF5dy4njmxR941l6rgtvfSB2zX3VlUIw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.29.7.tgz", + "integrity": "sha512-ONyr4+AZhKh8yKWInVxU9AXA9EbsyeLcL6V0dJy6M2/62vuvpGm29zzuymbTpdc451GEpDIdAyPLP3r+P61yKQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -879,14 +896,14 @@ } }, "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.28.6.tgz", - "integrity": "sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.29.7.tgz", + "integrity": "sha512-GtcpjFvanPfzNQi3eTitsCqtRRmmqzpy/A+yhTR1HaZo1Ly3EA8ZXxlPyHdR8/IuRMYc3E4wdGBewB2QKQjAaA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -896,14 +913,14 @@ } }, "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.6.tgz", - "integrity": "sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.29.7.tgz", + "integrity": "sha512-kibJgmEdX2iMwsHY2tSZNDgj8PwIlCQz7FK9KuGKO8zsuoUwSEhoNnNVp/emKWrbY4HeO6kkXfdMqRKKKXBm2A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -913,18 +930,18 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.6.tgz", - "integrity": "sha512-EF5KONAqC5zAqT783iMGuM2ZtmEBy+mJMOKl2BCvPZ2lVrwvXnB6o+OBWCS+CoeCCpVRF2sA2RBKUxvT8tQT5Q==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.29.7.tgz", + "integrity": "sha512-qV0OGGBVacduzQHE649JyCneOFI/maT+YKsO+K4Yi3xv2wTPNjM/W2o2gdzMwEAZz7fXNTHAe0NcSg30bIN69g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-globals": "^7.28.0", - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/helper-replace-supers": "^7.28.6", - "@babel/traverse": "^7.28.6" + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -934,14 +951,14 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.28.6.tgz", - "integrity": "sha512-bcc3k0ijhHbc2lEfpFHgx7eYw9KNXqOerKWfzbxEHUGKnS3sz9C4CNL9OiFN1297bDNfUiSO7DaLzbvHQQQ1BQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.29.7.tgz", + "integrity": "sha512-RK7/IyU5phpuCdBAuig5VkzG/EnbDaui5SQGdU9BFrHdV+mV4cUjLMQ9lJDjLNtWHsqtiefpGZUXQP2BiTYMsA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/template": "^7.28.6" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/template": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -951,14 +968,14 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz", - "integrity": "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.29.7.tgz", + "integrity": "sha512-iPX8aD6H9zV5s7ZsqTdNocPN/MGQ5sSMnElKrktxjJRMnB2jN/1p2+R7GkfD6CAYoVFqy5A4XnSIUeGgJzIWpg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.5" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -968,14 +985,14 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.28.6.tgz", - "integrity": "sha512-SljjowuNKB7q5Oayv4FoPzeB74g3QgLt8IVJw9ADvWy3QnUb/01aw8I4AVv8wYnPvQz2GDDZ/g3GhcNyDBI4Bg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.29.7.tgz", + "integrity": "sha512-3qc18hsD2RdZiyJNDNc7HQpv6xbncwh8FYtxNFFzclSyh/trPD9KkVR9BDECUjDLvb7yJVF15GfYUuC+LMkkiQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.28.5", - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -985,13 +1002,13 @@ } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", - "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.29.7.tgz", + "integrity": "sha512-6IvRRriEMqnBwD6chtxdLpMYCHWEzN+oL5cyQtjykya19UgzbmKhxmhZgKC/LHxS2nYr9Q/qYPZ5Lr6jOL9+yQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1001,14 +1018,14 @@ } }, "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.29.0.tgz", - "integrity": "sha512-zBPcW2lFGxdiD8PUnPwJjag2J9otbcLQzvbiOzDxpYXyCuYX9agOwMPGn1prVH0a4qzhCKu24rlH4c1f7yA8rw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.29.7.tgz", + "integrity": "sha512-2wiIyo2BjtgU7HufSeDnL9L2O7zr8jmhFKuSr65VpRkUiRKRNpb0mdlk56+XPPKoIrfHqzbMuglDvZun0RISsA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.28.5", - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1018,13 +1035,13 @@ } }, "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", - "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.29.7.tgz", + "integrity": "sha512-giOlEm/EFjfjr+te9NsdjkUo2v4f8rS/SXPumRVHAtbNcyNlvtREkU1dZzaIDclNpnaVhlCqRdFKhJBjBikzLg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1034,14 +1051,14 @@ } }, "node_modules/@babel/plugin-transform-explicit-resource-management": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.6.tgz", - "integrity": "sha512-Iao5Konzx2b6g7EPqTy40UZbcdXE126tTxVFr/nAIj+WItNxjKSYTEw3RC+A2/ZetmdJsgueL1KhaMCQHkLPIg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.29.7.tgz", + "integrity": "sha512-Rstj7coNz8sE+7Ju7ihpHLI564lsK5pUpNNlvptCIC/16E/S5hbl6n3kESPKdNRmqEWlpn5xpS5Q2dvXBsySLw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/plugin-transform-destructuring": "^7.28.5" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-transform-destructuring": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1051,13 +1068,13 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.6.tgz", - "integrity": "sha512-WitabqiGjV/vJ0aPOLSFfNY1u9U3R7W36B03r5I2KoNix+a3sOhJ3pKFB3R5It9/UiK78NiO0KE9P21cMhlPkw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.29.7.tgz", + "integrity": "sha512-zFpMOTLZBdW5LfObqcSbL6kefg4R4eLdmvS0wbN9M6D5Mym/sKm9toOoWyVOa+xDjvCnuWcHls2YonXwHvH3CQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1067,13 +1084,13 @@ } }, "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", - "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.29.7.tgz", + "integrity": "sha512-24B2nOy2TeJSMheqwPD4DDQOV/elLSIlKxjZt4i05H5AgdPdWR3n18HnNrcJ+j76WJd9gbwb9jPjNYUy6RautA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1083,14 +1100,14 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", - "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.29.7.tgz", + "integrity": "sha512-zeSIHh0+E1Um1WJRXCFlHQYu2ieJNdivLLjlBEp+dIBu3S51n+SZZmIXjxnItw6pz56Cn+KvK68BIBVsxq2JiQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1100,15 +1117,15 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", - "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.29.7.tgz", + "integrity": "sha512-otRWaHXE6fbAGkePvaj/kvs3HsqXfPhlnzwSOlnFgbqCPMd975dW+4wZ00WFBt+/YlBGcJwNrARQTOJOb4ZrIg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1118,13 +1135,13 @@ } }, "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.28.6.tgz", - "integrity": "sha512-Nr+hEN+0geQkzhbdgQVPoqr47lZbm+5fCUmO70722xJZd0Mvb59+33QLImGj6F+DkK3xgDi1YVysP8whD6FQAw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.29.7.tgz", + "integrity": "sha512-RRnE2+eon1rJAq8MnoF1b5kTpY1vU88twHcvcKMrsqP/jxIRqDVs9iJB5fqPuqyeFAW0wJo4MlUIPpQCq/aRsg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1134,13 +1151,13 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", - "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.29.7.tgz", + "integrity": "sha512-DZ/oLP21ZuWx1vKqnoNv6/tvEK48AQOBRai40CX9dTjGluvT/YZCyY3rryDtyUqCEoyNroy5KKPwX2iQCiRvyw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1150,13 +1167,13 @@ } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.6.tgz", - "integrity": "sha512-+anKKair6gpi8VsM/95kmomGNMD0eLz1NQ8+Pfw5sAwWH9fGYXT50E55ZpV0pHUHWf6IUTWPM+f/7AAff+wr9A==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.29.7.tgz", + "integrity": "sha512-A0H91hh6W8MFRkp5TqJmMr39jzGD1A1E1Ysiv2O06Sfbhkapm+XyIzxWCEh5kqwOZ1/8QZ0dY3SeQ7XBqfJd5Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1166,13 +1183,13 @@ } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", - "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.29.7.tgz", + "integrity": "sha512-hl1kwFZCCiDyfH25Xmco9jTrkPgnS9pmOzSG7W5I4SaGbLeqKv417hcU2RKmaxoPEgsoJh7ZPOrnPGq99bHoUg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1182,14 +1199,14 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", - "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.29.7.tgz", + "integrity": "sha512-fxtQoH3m5ywUSIfaH0FGCzWu4McsYon5bD3K4XnskC7f+OyQMj7rsOMi4NvvmJ83WwBAg4UCe+ov4VZlqEvyew==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1199,14 +1216,14 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.28.6.tgz", - "integrity": "sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.29.7.tgz", + "integrity": "sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1216,16 +1233,16 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.0.tgz", - "integrity": "sha512-PrujnVFbOdUpw4UHiVwKvKRLMMic8+eC0CuNlxjsyZUiBjhFdPsewdXCkveh2KqBA9/waD0W1b4hXSOBQJezpQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.7.tgz", + "integrity": "sha512-TM2ZcQLoG2/y4HODiStCo10DibYhWhGWAwVv+EQKmG/7GFl0N+AAmUiXOMKM+aiJ9XBJ9AHVZBvTzMnJ2sM3cQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.29.0" + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1235,14 +1252,14 @@ } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", - "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.29.7.tgz", + "integrity": "sha512-B4UkaTK3QpgCwJnrxKfMPKdo92CN7OKXAlpAAnM3UPu0Q0lCCk57ylA9AJbRy2v8dDKOPAAWcoR6CMyeoHwRCA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1252,14 +1269,14 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.29.0.tgz", - "integrity": "sha512-1CZQA5KNAD6ZYQLPw7oi5ewtDNxH/2vuCh+6SmvgDfhumForvs8a1o9n0UrEoBD8HU4djO2yWngTQlXl1NDVEQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.29.7.tgz", + "integrity": "sha512-vuFoLwr4qnv2xbZ16SQd6uPcH5FNrLHhk/Jzo++0XJFcaDsr4gjJVg6j398oMHiC+83k/GiBzviwF5KBJkPUtQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.28.5", - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1269,13 +1286,13 @@ } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", - "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.29.7.tgz", + "integrity": "sha512-fEo41GmsOUhOBlw8ioo6zvjX5Xc2Lqkzlyfqbpsk3eB6TReV18uhxZ0esfEokVbY2+PVJAQHNKxER6lGrzNd3A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1285,13 +1302,13 @@ } }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.28.6.tgz", - "integrity": "sha512-3wKbRgmzYbw24mDJXT7N+ADXw8BC/imU9yo9c9X9NKaLF1fW+e5H1U5QjMUBe4Qo4Ox/o++IyUkl1sVCLgevKg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.29.7.tgz", + "integrity": "sha512-idmp1dFaekP9GbcMvG24Kvw2BfhFZjHnNJCkV4WuIY4PskJzwI3f1N5OdgYke38T7rftO6ERulFRn2cFeZwRkg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1301,13 +1318,13 @@ } }, "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.28.6.tgz", - "integrity": "sha512-SJR8hPynj8outz+SlStQSwvziMN4+Bq99it4tMIf5/Caq+3iOc0JtKyse8puvyXkk3eFRIA5ID/XfunGgO5i6w==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.29.7.tgz", + "integrity": "sha512-zR7fv/z14OjgHl4AgRtkDBvBMhIzCxqV/qN/2BCRC7LjFwvuzjYe7gDWxC4Wl/SNsLM6SE1IWvRPYMgSJaUvNw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1317,17 +1334,17 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.6.tgz", - "integrity": "sha512-5rh+JR4JBC4pGkXLAcYdLHZjXudVxWMXbB6u6+E9lRL5TrGVbHt1TjxGbZ8CkmYw9zjkB7jutzOROArsqtncEA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.29.7.tgz", + "integrity": "sha512-Ld98jn4c0smUywL57m7SgsHq3OpThOa6LqZJif3G6jYOovPleoFhVrBJ1WegRApSFB2wu4+RelAj9AC9G08Z4A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/plugin-transform-destructuring": "^7.28.5", - "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/traverse": "^7.28.6" + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-transform-destructuring": "^7.29.7", + "@babel/plugin-transform-parameters": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1337,14 +1354,14 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", - "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.29.7.tgz", + "integrity": "sha512-Ea/diGcw0twB5IlZPO5sgET6fJsLJqPABqTuFWIR+iMPGPZJkATEIWx0wa+aEQ5UY1CBQyP/gkAiLEqn1vBiQA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1354,13 +1371,13 @@ } }, "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.28.6.tgz", - "integrity": "sha512-R8ja/Pyrv0OGAvAXQhSTmWyPJPml+0TMqXlO5w+AsMEiwb2fg3WkOvob7UxFSL3OIttFSGSRFKQsOhJ/X6HQdQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.29.7.tgz", + "integrity": "sha512-sLsyndxK2VwX6yNUOakMb7Sh553ZTe/vVM1XJ+9Z5aW1ytsc8xOIwmyk05NNjN60vkc5/KqoTH6hB4V41LJhng==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1370,14 +1387,14 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.6.tgz", - "integrity": "sha512-A4zobikRGJTsX9uqVFdafzGkqD30t26ck2LmOzAuLL8b2x6k3TIqRiT2xVvA9fNmFeTX484VpsdgmKNA0bS23w==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.29.7.tgz", + "integrity": "sha512-6GM1dhvK3gNODkXcEcMCOLEDCLSoZ/sBbro2Ax8HURyasQ4NshagQixkRFdh5niI6E4gmA/jYI/4aT7rRos3ZQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1387,13 +1404,13 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.27.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", - "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.29.7.tgz", + "integrity": "sha512-ZDOBqV/qLYJI0YElr8DcENEyARsFQeESqWXH6gZlghYXuPPjvweuDhP4VyEi4BlUBlLRFZVjxoZDMjxhLW766g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1403,14 +1420,14 @@ } }, "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.28.6.tgz", - "integrity": "sha512-piiuapX9CRv7+0st8lmuUlRSmX6mBcVeNQ1b4AYzJxfCMuBfB0vBXDiGSmm03pKJw1v6cZ8KSeM+oUnM6yAExg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.29.7.tgz", + "integrity": "sha512-/6Rz4DK1ETDEM/bWHsPHcaEe7ZaT1EqSXjtSP/L0DijOYuaUhiRiOKcwpZ8P7zR4xXEHc2ITdiCgBm9Tpyv9ug==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1420,15 +1437,15 @@ } }, "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.28.6.tgz", - "integrity": "sha512-b97jvNSOb5+ehyQmBpmhOCiUC5oVK4PMnpRvO7+ymFBoqYjeDHIU9jnrNUuwHOiL9RpGDoKBpSViarV+BU+eVA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.29.7.tgz", + "integrity": "sha512-+BNo06dnrzdNNqCm1X6YUaVv0DKk8Q+JYcoZfOkLhYWNCXzlwTSRq8zGWayT1csjcpNXV9CQTBRRbmTLZac5cA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-create-class-features-plugin": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1438,13 +1455,13 @@ } }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", - "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.29.7.tgz", + "integrity": "sha512-bOMRLQuI0A5ZqHq3OWJ89/rXpJ/NJrbVhXiP4zwPGMs6kpcVsuTUNjwoE30K0Qm3mf48a/TnRYYD6vPNqcg6jA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1454,13 +1471,13 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.0.tgz", - "integrity": "sha512-FijqlqMA7DmRdg/aINBSs04y8XNTYw/lr1gJ2WsmBnnaNw1iS43EPkJW+zK7z65auG3AWRFXWj+NcTQwYptUog==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.7.tgz", + "integrity": "sha512-rNNFV0DBAJp988xW2DOntfDoYn1eR8GGF5AT5vYc+rjyfaQkM242c9tZUHHPe7KYaiJizXPWhQTzzdbXySyhBw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1470,14 +1487,14 @@ } }, "node_modules/@babel/plugin-transform-regexp-modifiers": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.28.6.tgz", - "integrity": "sha512-QGWAepm9qxpaIs7UM9FvUSnCGlb8Ua1RhyM4/veAxLwt3gMat/LSGrZixyuj4I6+Kn9iwvqCyPTtbdxanYoWYg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.29.7.tgz", + "integrity": "sha512-mB5Fs0VWrJ42ZCmc8114v60qetdaUVNkj9PmSZRmanCZM3S9hm0CFRLjRmYIsuXav14l2jvZ+4T8iiCGnhj3nQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.28.5", - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1487,13 +1504,13 @@ } }, "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", - "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.29.7.tgz", + "integrity": "sha512-5+YhdpVgmfSmwZyLMftfaiffLRMHjzIRHFHHLdibcSyJm2pasMrKHrO3Ptrt2DRshjvpgjEJJ1zVW14WPq/6QA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1503,13 +1520,13 @@ } }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", - "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.29.7.tgz", + "integrity": "sha512-I+WYbGBAiCn7nA6xBrlgPH+MB7HWb4u8pv5S0Pv7OtwNvIFvCCb24YlttKEeUFVurfBCEaOTnuhlqsb7f0Z5Dg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1519,14 +1536,14 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.28.6.tgz", - "integrity": "sha512-9U4QObUC0FtJl05AsUcodau/RWDytrU6uKgkxu09mLR9HLDAtUMoPuuskm5huQsoktmsYpI+bGmq+iapDcriKA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.29.7.tgz", + "integrity": "sha512-/u5K1QWada7tbYNqTjMh96718g9NTwh9tfPJMsSmVsQwGT447FskV+KcfeXkXq2GWki4EM/MuTdmBec+hOuVTQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1536,13 +1553,13 @@ } }, "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", - "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.29.7.tgz", + "integrity": "sha512-BCHzNYJGe9l7EpwwDBN/ztlL2NYFFq8hp9ddjtUEM9f2O7S7kKV/lL6Fwo7IF7NSkYhPK2vO+86nIGltA90MsA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1552,13 +1569,13 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", - "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.29.7.tgz", + "integrity": "sha512-NCSEJ4sLFU2gqAub45HYh4fus2yQ36rr6ei6vpU7NdoJqCpxvEG8E6eJpscGyXP3VHD2Ny+fSXr04k1hoUrFqA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1568,13 +1585,13 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", - "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.29.7.tgz", + "integrity": "sha512-223mNGoTkBiTEWFoK+Q6Go3tueMRclO8vxxxxquNCYuNI4jWOofFKJRRDu6SDrB8Sgo1UEGW9T4GAQ8ZyRso1A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1584,13 +1601,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", - "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.29.7.tgz", + "integrity": "sha512-jCfXxSjf94lf4E0hKE0AByxF6F3/pVFqRdUUNkDJhsY0m1ZKjnN6ZYyMeHNpzflxb/0q5b7t3p+BE+SLF1WOtA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1600,14 +1617,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.28.6.tgz", - "integrity": "sha512-4Wlbdl/sIZjzi/8St0evF0gEZrgOswVO6aOzqxh1kDZOl9WmLrHq2HtGhnOJZmHZYKP8WZ1MDLCt5DAWwRo57A==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.29.7.tgz", + "integrity": "sha512-OgZ+zoAJgZLUCunsTRQ5LAjOywDv5zzZ2/hQ5aMw1pGXyY2rtE8/chXYUmu3AlVHKpm10KEdG9aMwbI/K76ZGw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.28.5", - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1617,14 +1634,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", - "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.29.7.tgz", + "integrity": "sha512-7D/x/23/d/3VqZ0QA+LGbZMlGwZjztBygSWWWsfTPoQ1oQ6Q1P6Mr3d0kk42XabyUVw+fha3LqdRsFqeKqvCyA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1634,14 +1651,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.28.6.tgz", - "integrity": "sha512-/wHc/paTUmsDYN7SZkpWxogTOBNnlx7nBQYfy6JJlCT7G3mVhltk3e++N7zV0XfgGsrqBxd4rJQt9H16I21Y1Q==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.29.7.tgz", + "integrity": "sha512-BLOhLht9DOJwIxlmp91wHvkXv1lguuHS3/FwUO8HL1H0u8s4hR1gASVFyilu9iGtcTRYqjTZmlsFFeQletntEg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.28.5", - "@babel/helper-plugin-utils": "^7.28.6" + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1651,76 +1668,77 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.2.tgz", - "integrity": "sha512-DYD23veRYGvBFhcTY1iUvJnDNpuqNd/BzBwCvzOTKUnJjKg5kpUBh3/u9585Agdkgj+QuygG7jLfOPWMa2KVNw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.29.0", - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6", - "@babel/helper-validator-option": "^7.27.1", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", - "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.6", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.7.tgz", + "integrity": "sha512-GYzX36n1nsciIb0uyH0GHwxwtNwPQIcpxSeiVLDtG/B7jB5xXgchnmL1f/jCX5o+pwnaDBtO60ONSJhEBJfxYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.29.7", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.29.7", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.29.7", + "@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": "^7.29.7", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.29.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.29.7", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-import-assertions": "^7.28.6", - "@babel/plugin-syntax-import-attributes": "^7.28.6", + "@babel/plugin-syntax-import-assertions": "^7.29.7", + "@babel/plugin-syntax-import-attributes": "^7.29.7", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.27.1", - "@babel/plugin-transform-async-generator-functions": "^7.29.0", - "@babel/plugin-transform-async-to-generator": "^7.28.6", - "@babel/plugin-transform-block-scoped-functions": "^7.27.1", - "@babel/plugin-transform-block-scoping": "^7.28.6", - "@babel/plugin-transform-class-properties": "^7.28.6", - "@babel/plugin-transform-class-static-block": "^7.28.6", - "@babel/plugin-transform-classes": "^7.28.6", - "@babel/plugin-transform-computed-properties": "^7.28.6", - "@babel/plugin-transform-destructuring": "^7.28.5", - "@babel/plugin-transform-dotall-regex": "^7.28.6", - "@babel/plugin-transform-duplicate-keys": "^7.27.1", - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.29.0", - "@babel/plugin-transform-dynamic-import": "^7.27.1", - "@babel/plugin-transform-explicit-resource-management": "^7.28.6", - "@babel/plugin-transform-exponentiation-operator": "^7.28.6", - "@babel/plugin-transform-export-namespace-from": "^7.27.1", - "@babel/plugin-transform-for-of": "^7.27.1", - "@babel/plugin-transform-function-name": "^7.27.1", - "@babel/plugin-transform-json-strings": "^7.28.6", - "@babel/plugin-transform-literals": "^7.27.1", - "@babel/plugin-transform-logical-assignment-operators": "^7.28.6", - "@babel/plugin-transform-member-expression-literals": "^7.27.1", - "@babel/plugin-transform-modules-amd": "^7.27.1", - "@babel/plugin-transform-modules-commonjs": "^7.28.6", - "@babel/plugin-transform-modules-systemjs": "^7.29.0", - "@babel/plugin-transform-modules-umd": "^7.27.1", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.29.0", - "@babel/plugin-transform-new-target": "^7.27.1", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.28.6", - "@babel/plugin-transform-numeric-separator": "^7.28.6", - "@babel/plugin-transform-object-rest-spread": "^7.28.6", - "@babel/plugin-transform-object-super": "^7.27.1", - "@babel/plugin-transform-optional-catch-binding": "^7.28.6", - "@babel/plugin-transform-optional-chaining": "^7.28.6", - "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/plugin-transform-private-methods": "^7.28.6", - "@babel/plugin-transform-private-property-in-object": "^7.28.6", - "@babel/plugin-transform-property-literals": "^7.27.1", - "@babel/plugin-transform-regenerator": "^7.29.0", - "@babel/plugin-transform-regexp-modifiers": "^7.28.6", - "@babel/plugin-transform-reserved-words": "^7.27.1", - "@babel/plugin-transform-shorthand-properties": "^7.27.1", - "@babel/plugin-transform-spread": "^7.28.6", - "@babel/plugin-transform-sticky-regex": "^7.27.1", - "@babel/plugin-transform-template-literals": "^7.27.1", - "@babel/plugin-transform-typeof-symbol": "^7.27.1", - "@babel/plugin-transform-unicode-escapes": "^7.27.1", - "@babel/plugin-transform-unicode-property-regex": "^7.28.6", - "@babel/plugin-transform-unicode-regex": "^7.27.1", - "@babel/plugin-transform-unicode-sets-regex": "^7.28.6", + "@babel/plugin-transform-arrow-functions": "^7.29.7", + "@babel/plugin-transform-async-generator-functions": "^7.29.7", + "@babel/plugin-transform-async-to-generator": "^7.29.7", + "@babel/plugin-transform-block-scoped-functions": "^7.29.7", + "@babel/plugin-transform-block-scoping": "^7.29.7", + "@babel/plugin-transform-class-properties": "^7.29.7", + "@babel/plugin-transform-class-static-block": "^7.29.7", + "@babel/plugin-transform-classes": "^7.29.7", + "@babel/plugin-transform-computed-properties": "^7.29.7", + "@babel/plugin-transform-destructuring": "^7.29.7", + "@babel/plugin-transform-dotall-regex": "^7.29.7", + "@babel/plugin-transform-duplicate-keys": "^7.29.7", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.29.7", + "@babel/plugin-transform-dynamic-import": "^7.29.7", + "@babel/plugin-transform-explicit-resource-management": "^7.29.7", + "@babel/plugin-transform-exponentiation-operator": "^7.29.7", + "@babel/plugin-transform-export-namespace-from": "^7.29.7", + "@babel/plugin-transform-for-of": "^7.29.7", + "@babel/plugin-transform-function-name": "^7.29.7", + "@babel/plugin-transform-json-strings": "^7.29.7", + "@babel/plugin-transform-literals": "^7.29.7", + "@babel/plugin-transform-logical-assignment-operators": "^7.29.7", + "@babel/plugin-transform-member-expression-literals": "^7.29.7", + "@babel/plugin-transform-modules-amd": "^7.29.7", + "@babel/plugin-transform-modules-commonjs": "^7.29.7", + "@babel/plugin-transform-modules-systemjs": "^7.29.7", + "@babel/plugin-transform-modules-umd": "^7.29.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.29.7", + "@babel/plugin-transform-new-target": "^7.29.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.29.7", + "@babel/plugin-transform-numeric-separator": "^7.29.7", + "@babel/plugin-transform-object-rest-spread": "^7.29.7", + "@babel/plugin-transform-object-super": "^7.29.7", + "@babel/plugin-transform-optional-catch-binding": "^7.29.7", + "@babel/plugin-transform-optional-chaining": "^7.29.7", + "@babel/plugin-transform-parameters": "^7.29.7", + "@babel/plugin-transform-private-methods": "^7.29.7", + "@babel/plugin-transform-private-property-in-object": "^7.29.7", + "@babel/plugin-transform-property-literals": "^7.29.7", + "@babel/plugin-transform-regenerator": "^7.29.7", + "@babel/plugin-transform-regexp-modifiers": "^7.29.7", + "@babel/plugin-transform-reserved-words": "^7.29.7", + "@babel/plugin-transform-shorthand-properties": "^7.29.7", + "@babel/plugin-transform-spread": "^7.29.7", + "@babel/plugin-transform-sticky-regex": "^7.29.7", + "@babel/plugin-transform-template-literals": "^7.29.7", + "@babel/plugin-transform-typeof-symbol": "^7.29.7", + "@babel/plugin-transform-unicode-escapes": "^7.29.7", + "@babel/plugin-transform-unicode-property-regex": "^7.29.7", + "@babel/plugin-transform-unicode-regex": "^7.29.7", + "@babel/plugin-transform-unicode-sets-regex": "^7.29.7", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.15", "babel-plugin-polyfill-corejs3": "^0.14.0", @@ -1762,33 +1780,33 @@ } }, "node_modules/@babel/template": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", - "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", - "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0", + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", "debug": "^4.3.1" }, "engines": { @@ -1796,13 +1814,13 @@ } }, "node_modules/@babel/types": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1838,9 +1856,9 @@ } }, "node_modules/@cypress/request": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.10.tgz", - "integrity": "sha512-hauBrOdvu08vOsagkZ/Aju5XuiZx6ldsLfByg1htFeldhex+PeMrYauANzFsMJeAA0+dyPLbDoX2OYuvVoLDkQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@cypress/request/-/request-4.0.1.tgz", + "integrity": "sha512-y20e+e6dFYkOUUJLVUZTsJRuTiXZaUQ32WD+R/ux/HBybbTx4ge7cNINcua0pU8+SNkKuRbOF12mBmzuzM8n5w==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1857,14 +1875,13 @@ "json-stringify-safe": "~5.0.1", "mime-types": "~2.1.19", "performance-now": "^2.1.0", - "qs": "~6.14.1", + "qs": "^6.15.2", "safe-buffer": "^5.1.2", "tough-cookie": "^5.0.0", - "tunnel-agent": "^0.6.0", - "uuid": "^8.3.2" + "tunnel-agent": "^0.6.0" }, "engines": { - "node": ">= 6" + "node": ">= 14.17.0" } }, "node_modules/@cypress/xvfb": { @@ -1934,188 +1951,562 @@ } } }, - "node_modules/@esbuild/linux-x64": { + "node_modules/@esbuild/aix-ppc64": { "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", "cpu": [ - "x64" + "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ - "linux" + "aix" ], "engines": { "node": ">=12" } }, - "node_modules/@headlessui/vue": { - "version": "1.7.16", - "resolved": "https://registry.npmjs.org/@headlessui/vue/-/vue-1.7.16.tgz", - "integrity": "sha512-nKT+nf/q6x198SsyK54mSszaQl/z+QxtASmgMEJtpxSX2Q0OPJX0upS/9daDyiECpeAsvjkoOrm2O/6PyBQ+Qg==", + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=10" - }, - "peerDependencies": { - "vue": "^3.2.0" + "node": ">=12" } }, - "node_modules/@iconify-json/simple-icons": { - "version": "1.2.35", - "resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.35.tgz", - "integrity": "sha512-PAHZZn6P5ToHMhmEeeh/O96E/Ep4PctN44N64dWYbDasEvbVoN6x62m+Doz8au0SVS4/zYEMAsDO6TdO9ep84Q==", + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "@iconify/types": "*" + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" } }, - "node_modules/@iconify/types": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", - "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", - "dev": true - }, - "node_modules/@inquirer/checkbox": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.0.4.tgz", - "integrity": "sha512-fYAKCAcGNMdfjL6hZTRUwkIByQ8EIZCXKrIQZH7XjADnN/xvRUhj8UdBbpC4zoUzvChhkSC/zRKaP/tDs3dZpg==", + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "@inquirer/core": "^10.1.2", - "@inquirer/figures": "^1.0.9", - "@inquirer/type": "^3.0.2", - "ansi-escapes": "^4.3.2", - "yoctocolors-cjs": "^2.1.2" - }, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" + "node": ">=12" } }, - "node_modules/@inquirer/confirm": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.1.tgz", - "integrity": "sha512-vVLSbGci+IKQvDOtzpPTCOiEJCNidHcAq9JYVoWTW0svb5FiwSLotkM+JXNXejfjnzVYV9n0DTBythl9+XgTxg==", + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "@inquirer/core": "^10.1.2", - "@inquirer/type": "^3.0.2" - }, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" + "node": ">=12" } }, - "node_modules/@inquirer/core": { - "version": "10.1.15", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.1.15.tgz", - "integrity": "sha512-8xrp836RZvKkpNbVvgWUlxjT4CraKk2q+I3Ksy+seI2zkcE+y6wNs1BVhgcv8VyImFecUhdQrYLdW32pAjwBdA==", + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@inquirer/figures": "^1.0.13", - "@inquirer/type": "^3.0.8", - "ansi-escapes": "^4.3.2", - "cli-width": "^4.1.0", - "mute-stream": "^2.0.0", - "signal-exit": "^4.1.0", - "wrap-ansi": "^6.2.0", - "yoctocolors-cjs": "^2.1.2" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "node": ">=12" } }, - "node_modules/@inquirer/core/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=12" } }, - "node_modules/@inquirer/core/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=7.0.0" + "node": ">=12" } }, - "node_modules/@inquirer/core/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@inquirer/core/node_modules/mute-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", - "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": ">=12" } }, - "node_modules/@inquirer/core/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=12" } }, - "node_modules/@inquirer/core/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/@inquirer/editor": { - "version": "4.2.16", - "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.16.tgz", - "integrity": "sha512-iSzLjT4C6YKp2DU0fr8T7a97FnRRxMO6CushJnW5ktxLNM2iNeuyUuUA5255eOLPORoGYCrVnuDOEBdGkHGkpw==", + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@inquirer/core": "^10.1.15", - "@inquirer/external-editor": "^1.0.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@headlessui/vue": { + "version": "1.7.16", + "resolved": "https://registry.npmjs.org/@headlessui/vue/-/vue-1.7.16.tgz", + "integrity": "sha512-nKT+nf/q6x198SsyK54mSszaQl/z+QxtASmgMEJtpxSX2Q0OPJX0upS/9daDyiECpeAsvjkoOrm2O/6PyBQ+Qg==", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/@iconify-json/simple-icons": { + "version": "1.2.35", + "resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.35.tgz", + "integrity": "sha512-PAHZZn6P5ToHMhmEeeh/O96E/Ep4PctN44N64dWYbDasEvbVoN6x62m+Doz8au0SVS4/zYEMAsDO6TdO9ep84Q==", + "dev": true, + "dependencies": { + "@iconify/types": "*" + } + }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "dev": true + }, + "node_modules/@inquirer/checkbox": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.0.4.tgz", + "integrity": "sha512-fYAKCAcGNMdfjL6hZTRUwkIByQ8EIZCXKrIQZH7XjADnN/xvRUhj8UdBbpC4zoUzvChhkSC/zRKaP/tDs3dZpg==", + "dev": true, + "dependencies": { + "@inquirer/core": "^10.1.2", + "@inquirer/figures": "^1.0.9", + "@inquirer/type": "^3.0.2", + "ansi-escapes": "^4.3.2", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + } + }, + "node_modules/@inquirer/confirm": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.1.tgz", + "integrity": "sha512-vVLSbGci+IKQvDOtzpPTCOiEJCNidHcAq9JYVoWTW0svb5FiwSLotkM+JXNXejfjnzVYV9n0DTBythl9+XgTxg==", + "dev": true, + "dependencies": { + "@inquirer/core": "^10.1.2", + "@inquirer/type": "^3.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + } + }, + "node_modules/@inquirer/core": { + "version": "10.1.15", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.1.15.tgz", + "integrity": "sha512-8xrp836RZvKkpNbVvgWUlxjT4CraKk2q+I3Ksy+seI2zkcE+y6wNs1BVhgcv8VyImFecUhdQrYLdW32pAjwBdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/figures": "^1.0.13", + "@inquirer/type": "^3.0.8", + "ansi-escapes": "^4.3.2", + "cli-width": "^4.1.0", + "mute-stream": "^2.0.0", + "signal-exit": "^4.1.0", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/core/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@inquirer/core/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@inquirer/core/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@inquirer/core/node_modules/mute-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", + "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", + "dev": true, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@inquirer/core/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@inquirer/core/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@inquirer/editor": { + "version": "4.2.16", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.16.tgz", + "integrity": "sha512-iSzLjT4C6YKp2DU0fr8T7a97FnRRxMO6CushJnW5ktxLNM2iNeuyUuUA5255eOLPORoGYCrVnuDOEBdGkHGkpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.15", + "@inquirer/external-editor": "^1.0.0", "@inquirer/type": "^3.0.8" }, "engines": { @@ -2492,18 +2883,18 @@ "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==", "dev": true }, - "node_modules/@noble/hashes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "node_modules/@nodable/entities": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-3.0.0.tgz", + "integrity": "sha512-8L9xFeTYKhm49xfIypoe2W5wV1m/3Z58kT+7kR9A8OyFxcPduI4VmxaUMQyKYrRjUoLLSXv6EKKID5Tvj9cUVw==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/nodable" + } + ], + "license": "MIT" }, "node_modules/@octokit/app": { "version": "14.1.0", @@ -3113,865 +3504,512 @@ "@parcel/watcher-linux-arm64-glibc": "2.5.0", "@parcel/watcher-linux-arm64-musl": "2.5.0", "@parcel/watcher-linux-x64-glibc": "2.5.0", - "@parcel/watcher-linux-x64-musl": "2.5.0", - "@parcel/watcher-win32-arm64": "2.5.0", - "@parcel/watcher-win32-ia32": "2.5.0", - "@parcel/watcher-win32-x64": "2.5.0" - } - }, - "node_modules/@parcel/watcher-linux-x64-glibc": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.0.tgz", - "integrity": "sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-x64-musl": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.0.tgz", - "integrity": "sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@peculiar/asn1-cms": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.6.1.tgz", - "integrity": "sha512-vdG4fBF6Lkirkcl53q6eOdn3XYKt+kJTG59edgRZORlg/3atWWEReRCx5rYE1ZzTTX6vLK5zDMjHh7vbrcXGtw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.1", - "@peculiar/asn1-x509-attr": "^2.6.1", - "asn1js": "^3.0.6", - "tslib": "^2.8.1" - } - }, - "node_modules/@peculiar/asn1-csr": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-csr/-/asn1-csr-2.6.1.tgz", - "integrity": "sha512-WRWnKfIocHyzFYQTka8O/tXCiBquAPSrRjXbOkHbO4qdmS6loffCEGs+rby6WxxGdJCuunnhS2duHURhjyio6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.1", - "asn1js": "^3.0.6", - "tslib": "^2.8.1" - } - }, - "node_modules/@peculiar/asn1-ecc": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.6.1.tgz", - "integrity": "sha512-+Vqw8WFxrtDIN5ehUdvlN2m73exS2JVG0UAyfVB31gIfor3zWEAQPD+K9ydCxaj3MLen9k0JhKpu9LqviuCE1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.1", - "asn1js": "^3.0.6", - "tslib": "^2.8.1" - } - }, - "node_modules/@peculiar/asn1-pfx": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-pfx/-/asn1-pfx-2.6.1.tgz", - "integrity": "sha512-nB5jVQy3MAAWvq0KY0R2JUZG8bO/bTLpnwyOzXyEh/e54ynGTatAR+csOnXkkVD9AFZ2uL8Z7EV918+qB1qDvw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@peculiar/asn1-cms": "^2.6.1", - "@peculiar/asn1-pkcs8": "^2.6.1", - "@peculiar/asn1-rsa": "^2.6.1", - "@peculiar/asn1-schema": "^2.6.0", - "asn1js": "^3.0.6", - "tslib": "^2.8.1" - } - }, - "node_modules/@peculiar/asn1-pkcs8": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs8/-/asn1-pkcs8-2.6.1.tgz", - "integrity": "sha512-JB5iQ9Izn5yGMw3ZG4Nw3Xn/hb/G38GYF3lf7WmJb8JZUydhVGEjK/ZlFSWhnlB7K/4oqEs8HnfFIKklhR58Tw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.1", - "asn1js": "^3.0.6", - "tslib": "^2.8.1" - } - }, - "node_modules/@peculiar/asn1-pkcs9": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs9/-/asn1-pkcs9-2.6.1.tgz", - "integrity": "sha512-5EV8nZoMSxeWmcxWmmcolg22ojZRgJg+Y9MX2fnE2bGRo5KQLqV5IL9kdSQDZxlHz95tHvIq9F//bvL1OeNILw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@peculiar/asn1-cms": "^2.6.1", - "@peculiar/asn1-pfx": "^2.6.1", - "@peculiar/asn1-pkcs8": "^2.6.1", - "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.1", - "@peculiar/asn1-x509-attr": "^2.6.1", - "asn1js": "^3.0.6", - "tslib": "^2.8.1" - } - }, - "node_modules/@peculiar/asn1-rsa": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.6.1.tgz", - "integrity": "sha512-1nVMEh46SElUt5CB3RUTV4EG/z7iYc7EoaDY5ECwganibQPkZ/Y2eMsTKB/LeyrUJ+W/tKoD9WUqIy8vB+CEdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.1", - "asn1js": "^3.0.6", - "tslib": "^2.8.1" - } - }, - "node_modules/@peculiar/asn1-schema": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.6.0.tgz", - "integrity": "sha512-xNLYLBFTBKkCzEZIw842BxytQQATQv+lDTCEMZ8C196iJcJJMBUZxrhSTxLaohMyKK8QlzRNTRkUmanucnDSqg==", - "dev": true, - "license": "MIT", - "dependencies": { - "asn1js": "^3.0.6", - "pvtsutils": "^1.3.6", - "tslib": "^2.8.1" - } - }, - "node_modules/@peculiar/asn1-x509": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.6.1.tgz", - "integrity": "sha512-O9jT5F1A2+t3r7C4VT7LYGXqkGLK7Kj1xFpz7U0isPrubwU5PbDoyYtx6MiGst29yq7pXN5vZbQFKRCP+lLZlA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@peculiar/asn1-schema": "^2.6.0", - "asn1js": "^3.0.6", - "pvtsutils": "^1.3.6", - "tslib": "^2.8.1" - } - }, - "node_modules/@peculiar/asn1-x509-attr": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509-attr/-/asn1-x509-attr-2.6.1.tgz", - "integrity": "sha512-tlW6cxoHwgcQghnJwv3YS+9OO1737zgPogZ+CgWRUK4roEwIPzRH4JEiG770xe5HX2ATfCpmX60gurfWIF9dcQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.1", - "asn1js": "^3.0.6", - "tslib": "^2.8.1" - } - }, - "node_modules/@peculiar/x509": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/@peculiar/x509/-/x509-1.14.3.tgz", - "integrity": "sha512-C2Xj8FZ0uHWeCXXqX5B4/gVFQmtSkiuOolzAgutjTfseNOHT3pUjljDZsTSxXFGgio54bCzVFqmEOUrIVk8RDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@peculiar/asn1-cms": "^2.6.0", - "@peculiar/asn1-csr": "^2.6.0", - "@peculiar/asn1-ecc": "^2.6.0", - "@peculiar/asn1-pkcs9": "^2.6.0", - "@peculiar/asn1-rsa": "^2.6.0", - "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.0", - "pvtsutils": "^1.3.6", - "reflect-metadata": "^0.2.2", - "tslib": "^2.8.1", - "tsyringe": "^4.10.0" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@php-wasm/cli-util": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/cli-util/-/cli-util-3.0.52.tgz", - "integrity": "sha512-znW/+lDWIqlCxe4vhaNuT7Cw3PkTwCFZ0raiivjvYtlHmQc0nSKGMY+8gH3bBkpxEnjXrR0RSmU2UuzQFUM5JA==", - "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@php-wasm/util": "3.0.52", - "fast-xml-parser": "^5.3.4", - "jsonc-parser": "3.3.1" - }, - "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@php-wasm/fs-journal": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/fs-journal/-/fs-journal-3.0.52.tgz", - "integrity": "sha512-OaG1VAIvG2c/7IXfM4Q7tSETq116kXsf+EPzqtWev4oNGU/fMlAEDByRmHC7DYI4Da0tT9YwpVYPiByj4zae1g==", - "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@php-wasm/logger": "3.0.52", - "@php-wasm/node": "3.0.52", - "@php-wasm/universal": "3.0.52", - "@php-wasm/util": "3.0.52", - "express": "4.22.0", - "ini": "4.1.2", - "wasm-feature-detect": "1.8.0", - "ws": "8.18.3", - "yargs": "17.7.2" - }, - "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@php-wasm/fs-journal/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@php-wasm/logger": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/logger/-/logger-3.0.52.tgz", - "integrity": "sha512-9NlGe5sV0SC1Zb6UfuNJ4XO3HT9pr0NKjv5PRAHlaF2yNCJ3T6O+LCGJiaojWjs2nKqw293LMeHEKFEwe+Pfgg==", - "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@php-wasm/node-polyfills": "3.0.52" - }, - "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@php-wasm/node": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/node/-/node-3.0.52.tgz", - "integrity": "sha512-V+ds3PtPrzuSCDHnrDahZdTZbGXynLH1SEH+dSny1taF9WDyp/7Gc73s3E/pCn/8iAB6kSut25dpc1gkzmktOQ==", - "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@php-wasm/logger": "3.0.52", - "@php-wasm/node-7-4": "3.0.52", - "@php-wasm/node-8-0": "3.0.52", - "@php-wasm/node-8-1": "3.0.52", - "@php-wasm/node-8-2": "3.0.52", - "@php-wasm/node-8-3": "3.0.52", - "@php-wasm/node-8-4": "3.0.52", - "@php-wasm/node-8-5": "3.0.52", - "@php-wasm/node-polyfills": "3.0.52", - "@php-wasm/universal": "3.0.52", - "@php-wasm/util": "3.0.52", - "@wp-playground/common": "3.0.52", - "express": "4.22.0", - "ini": "4.1.2", - "wasm-feature-detect": "1.8.0", - "ws": "8.18.3", - "yargs": "17.7.2" - }, - "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@php-wasm/node-7-4": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/node-7-4/-/node-7-4-3.0.52.tgz", - "integrity": "sha512-P30l0/lleRLnhob9p3L3o4h2EDH76Fd9fQ+fFvGH8N3aYaNJysug3lKR6hnbQzTQab/xU2JFFUg5Faw3cJfT1w==", - "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@php-wasm/universal": "3.0.52", - "ini": "4.1.2", - "wasm-feature-detect": "1.8.0", - "ws": "8.18.3" - }, - "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@php-wasm/node-7-4/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@php-wasm/node-8-0": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/node-8-0/-/node-8-0-3.0.52.tgz", - "integrity": "sha512-sm3zsGyGDLd6+b5/VsMxfHJvaREOlYcqPI7WqyrieQCVAg5IckQzeYdVpbQjMhfiAHRprSqyvEV6bz+iQCFiwg==", - "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@php-wasm/universal": "3.0.52", - "ini": "4.1.2", - "wasm-feature-detect": "1.8.0", - "ws": "8.18.3" - }, - "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@php-wasm/node-8-0/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@php-wasm/node-8-1": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/node-8-1/-/node-8-1-3.0.52.tgz", - "integrity": "sha512-6jnMLEsGH6JNHst52Wv9/UHEL5BJb+IOhMW4cG+OwcaqHb5cXq16j9Ak2djwnGgxOJ6geg2wqr1dVXR6fLeXXw==", - "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@php-wasm/universal": "3.0.52", - "ini": "4.1.2", - "wasm-feature-detect": "1.8.0", - "ws": "8.18.3" - }, - "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@php-wasm/node-8-1/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "@parcel/watcher-linux-x64-musl": "2.5.0", + "@parcel/watcher-win32-arm64": "2.5.0", + "@parcel/watcher-win32-ia32": "2.5.0", + "@parcel/watcher-win32-x64": "2.5.0" } }, - "node_modules/@php-wasm/node-8-2": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/node-8-2/-/node-8-2-3.0.52.tgz", - "integrity": "sha512-fjGd/J2vUApLgQbviCpnqAZ6dxhVy6faBxL3Rg3ZCajH/NASd+Tn+z9GacnLjQms0zlphk/SbFLZdAU2WY6x8A==", + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.0.tgz", + "integrity": "sha512-qlX4eS28bUcQCdribHkg/herLe+0A9RyYC+mm2PXpncit8z5b3nSqGVzMNR3CmtAOgRutiZ02eIJJgP/b1iEFQ==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@php-wasm/universal": "3.0.52", - "ini": "4.1.2", - "wasm-feature-detect": "1.8.0", - "ws": "8.18.3" - }, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" + "node": ">= 10.0.0" }, - "optionalDependencies": { - "fs-ext": "2.1.1" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@php-wasm/node-8-2/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.0.tgz", + "integrity": "sha512-hyZ3TANnzGfLpRA2s/4U1kbw2ZI4qGxaRJbBH2DCSREFfubMswheh8TeiC1sGZ3z2jUf3s37P0BBlrD3sjVTUw==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "ISC", + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@php-wasm/node-8-3": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/node-8-3/-/node-8-3-3.0.52.tgz", - "integrity": "sha512-88q2+OoQ0Zq1DVC+LFhc+F/bG9QnoRRDBZUgFSAOV0GB055F+oU9YXbM9du8OSuUDQ1OEVe+L0VM5sgDfDStIw==", + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.0.tgz", + "integrity": "sha512-9rhlwd78saKf18fT869/poydQK8YqlU26TMiNg7AIu7eBp9adqbJZqmdFOsbZ5cnLp5XvRo9wcFmNHgHdWaGYA==", + "cpu": [ + "x64" + ], "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@php-wasm/universal": "3.0.52", - "ini": "4.1.2", - "wasm-feature-detect": "1.8.0", - "ws": "8.18.3" - }, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" + "node": ">= 10.0.0" }, - "optionalDependencies": { - "fs-ext": "2.1.1" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@php-wasm/node-8-3/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.0.tgz", + "integrity": "sha512-syvfhZzyM8kErg3VF0xpV8dixJ+RzbUaaGaeb7uDuz0D3FK97/mZ5AJQ3XNnDsXX7KkFNtyQyFrXZzQIcN49Tw==", + "cpu": [ + "x64" + ], "dev": true, - "license": "ISC", + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@php-wasm/node-8-4": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/node-8-4/-/node-8-4-3.0.52.tgz", - "integrity": "sha512-8B38E1yZQV/8fy9wkQHj23n/uW+2UhZIfcwoBcnRTztONeVKHzPl6rOLBylzJwpg3CXwJ7YJam/MhVkQEfP28g==", + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.0.tgz", + "integrity": "sha512-0VQY1K35DQET3dVYWpOaPFecqOT9dbuCfzjxoQyif1Wc574t3kOSkKevULddcR9znz1TcklCE7Ht6NIxjvTqLA==", + "cpu": [ + "arm" + ], "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@php-wasm/universal": "3.0.52", - "ini": "4.1.2", - "wasm-feature-detect": "1.8.0", - "ws": "8.18.3" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" + "node": ">= 10.0.0" }, - "optionalDependencies": { - "fs-ext": "2.1.1" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@php-wasm/node-8-4/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.0.tgz", + "integrity": "sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==", + "cpu": [ + "arm" + ], "dev": true, - "license": "ISC", + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@php-wasm/node-8-5": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/node-8-5/-/node-8-5-3.0.52.tgz", - "integrity": "sha512-4UawC56VhV6m2YHuxsY0e/Je9F7JWAvFppJo3aBGUWEqQsOvD5lmiZZF/DgyfWJacfvimw3/eeqo1U63+G3e5Q==", + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.0.tgz", + "integrity": "sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@php-wasm/universal": "3.0.52", - "ini": "4.1.2", - "wasm-feature-detect": "1.8.0", - "ws": "8.18.3" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" + "node": ">= 10.0.0" }, - "optionalDependencies": { - "fs-ext": "2.1.1" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@php-wasm/node-8-5/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.0.tgz", + "integrity": "sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "ISC", + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@php-wasm/node-polyfills": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/node-polyfills/-/node-polyfills-3.0.52.tgz", - "integrity": "sha512-lMvGe+SHQVROSfAGpX/w8bCQukmBrS21TAOdoMUoFwUmxKwp1Ztfw+oYqm5maBR1jVoporog3F/KomtUcgab5Q==", + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.0.tgz", + "integrity": "sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==", + "cpu": [ + "x64" + ], "dev": true, - "license": "GPL-2.0-or-later", - "optionalDependencies": { - "fs-ext": "2.1.1" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@php-wasm/node/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.0.tgz", + "integrity": "sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==", + "cpu": [ + "x64" + ], "dev": true, - "license": "ISC", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@php-wasm/progress": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/progress/-/progress-3.0.52.tgz", - "integrity": "sha512-v41iBYG4nDNWdfQCZDbrn2Tmh0JnPQ1ElFl9kUXX/GExvM8LLXycVOp3O5y3+0i/tXuciJoKWj+9NF/PEuLDvw==", + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.0.tgz", + "integrity": "sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@php-wasm/logger": "3.0.52", - "@php-wasm/node-polyfills": "3.0.52" - }, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" + "node": ">= 10.0.0" }, - "optionalDependencies": { - "fs-ext": "2.1.1" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@php-wasm/scopes": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/scopes/-/scopes-3.0.52.tgz", - "integrity": "sha512-AMb8RcVqIyqGe2wS7Lp4i3lDwsQlKXkqwarRCxJpgWCUP2CkYELOXTJqrR2SvLUf8HOYO5suH69CvAq+N15zeg==", + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.0.tgz", + "integrity": "sha512-+rgpsNRKwo8A53elqbbHXdOMtY/tAtTzManTWShB5Kk54N8Q9mzNWV7tV+IbGueCbcj826MfWGU3mprWtuf1TA==", + "cpu": [ + "ia32" + ], "dev": true, - "license": "GPL-2.0-or-later", + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" + "node": ">= 10.0.0" }, - "optionalDependencies": { - "fs-ext": "2.1.1" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@php-wasm/stream-compression": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/stream-compression/-/stream-compression-3.0.52.tgz", - "integrity": "sha512-BF4RzHm4kwaAIuL6SZG4V9YxtmDkEHWg4+nOOooM7KEzwc63V6lbujeAq/HwM/mqNBO2J+LW9ZJ+k4yCF7okSg==", + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.0.tgz", + "integrity": "sha512-lPrxve92zEHdgeff3aiu4gDOIt4u7sJYha6wbdEZDCDUhtjTsOMiaJzG5lMY4GkWH8p0fMmO2Ppq5G5XXG+DQw==", + "cpu": [ + "x64" + ], "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@php-wasm/node-polyfills": "3.0.52", - "@php-wasm/util": "3.0.52" + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" }, - "optionalDependencies": { - "fs-ext": "2.1.1" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@php-wasm/universal": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/universal/-/universal-3.0.52.tgz", - "integrity": "sha512-P88tyWsOjr35MSNOvQPono2bzkuorjXvQ3RFUV6yGHhRZXOMe+dzPcJ7EsJ5AOxxvhvshB4VLwxpyUAcFtj6Ww==", + "node_modules/@php-wasm/cli-util": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/cli-util/-/cli-util-3.1.45.tgz", + "integrity": "sha512-+ht22B6KPUsn5ORtApE5xYq+uIb7/Qv/NSOxYgNGSWf3O1rpxkbOMeCxtE7H3dvazJIlSF+/nsVHpHkcTZGOpA==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { - "@php-wasm/logger": "3.0.52", - "@php-wasm/node-polyfills": "3.0.52", - "@php-wasm/progress": "3.0.52", - "@php-wasm/stream-compression": "3.0.52", - "@php-wasm/util": "3.0.52", - "ini": "4.1.2" - }, - "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" + "@php-wasm/util": "3.1.45", + "fast-xml-parser": "^5.8.0", + "jsonc-parser": "3.3.1" }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@php-wasm/universal/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", - "dev": true, - "license": "ISC", "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, - "node_modules/@php-wasm/util": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/util/-/util-3.0.52.tgz", - "integrity": "sha512-82u4Q13IPcL91CusRDy8k9L38zQrqqRO04pnTBJ3uMH1wZy4pAYZ305mKxce1EIU7QqPay/S69VdnWh+K4tOvA==", + "node_modules/@php-wasm/logger": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/logger/-/logger-3.1.45.tgz", + "integrity": "sha512-FYWGxaRZTM+aiRQ6/LlnFAdsixJ7VWQpM8Fe/61yWgpBamb1w3NEDRhYVR5DNjYWJVI5ha6pVxIsHtw018iA7g==", "dev": true, - "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" + "license": "GPL-2.0-or-later", + "engines": { + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, - "node_modules/@php-wasm/web": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/web/-/web-3.0.52.tgz", - "integrity": "sha512-fjSgAOMo2dX5yknN8nAM6Ctd/sovZGIf6dEQeDzXoJm+dHlop6AMUa7FSj4/KXyENim6xcDRpAgf5yMcGiRyFw==", + "node_modules/@php-wasm/node": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/node/-/node-3.1.45.tgz", + "integrity": "sha512-IFnGdNsQ0g8RwpFzg3gAt8VckFwshQ7g2Izwt+i+wi2Rtnj54DcPZpfMwliiq+c1XU1//jtXHBdczbwR75yW7A==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { - "@php-wasm/fs-journal": "3.0.52", - "@php-wasm/logger": "3.0.52", - "@php-wasm/universal": "3.0.52", - "@php-wasm/util": "3.0.52", - "@php-wasm/web-7-4": "3.0.52", - "@php-wasm/web-8-0": "3.0.52", - "@php-wasm/web-8-1": "3.0.52", - "@php-wasm/web-8-2": "3.0.52", - "@php-wasm/web-8-3": "3.0.52", - "@php-wasm/web-8-4": "3.0.52", - "@php-wasm/web-8-5": "3.0.52", - "@php-wasm/web-service-worker": "3.0.52", - "@wp-playground/common": "3.0.52", - "express": "4.22.0", - "ini": "4.1.2", - "selfsigned": "5.5.0", + "@php-wasm/cli-util": "3.1.45", + "@php-wasm/logger": "3.1.45", + "@php-wasm/node-5-2": "3.1.45", + "@php-wasm/node-7-4": "3.1.45", + "@php-wasm/node-8-0": "3.1.45", + "@php-wasm/node-8-1": "3.1.45", + "@php-wasm/node-8-2": "3.1.45", + "@php-wasm/node-8-3": "3.1.45", + "@php-wasm/node-8-4": "3.1.45", + "@php-wasm/node-8-5": "3.1.45", + "@php-wasm/universal": "3.1.45", + "@php-wasm/util": "3.1.45", + "fs-ext-extra-prebuilt": "2.2.7", "wasm-feature-detect": "1.8.0", - "ws": "8.18.3", - "yargs": "17.7.2" + "ws": "8.21.0" }, "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, - "node_modules/@php-wasm/web-7-4": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/web-7-4/-/web-7-4-3.0.52.tgz", - "integrity": "sha512-t+y8GXOl5WkaD7LeRfOn6iatgFy5ntc2X480FyoJoZmhDVj8e+wsMfZ/aAWDrkrV84tVLWj1GKTVAcBSGmuS2w==", + "node_modules/@php-wasm/node-5-2": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/node-5-2/-/node-5-2-3.1.45.tgz", + "integrity": "sha512-mKYOI8/eWE7Gu9wOOwtcxGrhOfCfGlIqT3Jr1RK0qCsZ/GkiW2/EalsNC5wSWbaL9qdh4JUbXUoF7mE3dc+KRQ==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { - "@php-wasm/universal": "3.0.52", - "ini": "4.1.2", + "@php-wasm/universal": "3.1.45", "wasm-feature-detect": "1.8.0" }, "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@php-wasm/web-7-4/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, - "node_modules/@php-wasm/web-8-0": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/web-8-0/-/web-8-0-3.0.52.tgz", - "integrity": "sha512-iJlCd8cwk2GbKiTtUE1VmUzv4Z5yiJDmHgcNVdRh2tu1zVxLO4pLlG938bx7UPo6mm6L9SmgBx2kdgjOCmCcWQ==", + "node_modules/@php-wasm/node-7-4": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/node-7-4/-/node-7-4-3.1.45.tgz", + "integrity": "sha512-3+VgXIL4y4Acb/OyNQAsIfz5I5GYlFmjw4M8l2Xx8TNBrixuOEO5vHmMoTssynZlmjoTLxBBzL2SaRHoubwi6g==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { - "@php-wasm/universal": "3.0.52", - "ini": "4.1.2", + "@php-wasm/universal": "3.1.45", "wasm-feature-detect": "1.8.0" }, "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, - "node_modules/@php-wasm/web-8-0/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", + "node_modules/@php-wasm/node-8-0": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/node-8-0/-/node-8-0-3.1.45.tgz", + "integrity": "sha512-6yJaW+mxgBWAy80IYRU41bh1LH4WsuDgqEWiHSumJcKOcNljSedUbm+YuLTY+Pnsov7u5yzkaBskslxGXcOlIQ==", "dev": true, - "license": "ISC", + "license": "GPL-2.0-or-later", + "dependencies": { + "@php-wasm/universal": "3.1.45", + "wasm-feature-detect": "1.8.0" + }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, - "node_modules/@php-wasm/web-8-1": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/web-8-1/-/web-8-1-3.0.52.tgz", - "integrity": "sha512-0XfiFIOBIpYAb9zVuyOpXCQn/2g6OgIDAX/u2M3a3x4NxeLg2txvazU+cWRzhGRsSRFgptpqO69ojmhF1JaG7w==", + "node_modules/@php-wasm/node-8-1": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/node-8-1/-/node-8-1-3.1.45.tgz", + "integrity": "sha512-/5haLrmCySu40aDGtVAOukDBNYzCJ0JTXslXs36Rh8P9V2nlctVGO+Kp1m/74yCtdoJrZsRrBnVqKBCliVQjdg==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { - "@php-wasm/universal": "3.0.52", - "ini": "4.1.2", + "@php-wasm/universal": "3.1.45", "wasm-feature-detect": "1.8.0" }, "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, - "node_modules/@php-wasm/web-8-1/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", + "node_modules/@php-wasm/node-8-2": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/node-8-2/-/node-8-2-3.1.45.tgz", + "integrity": "sha512-fGsSHw6OTnNyjr6k87OqV8SYqRZlDrWYVSXFkOywXUbBvyAYeuttxHffYC4VoRZdRz+Ygu+2k2aPE06jpTTBFw==", "dev": true, - "license": "ISC", + "license": "GPL-2.0-or-later", + "dependencies": { + "@php-wasm/universal": "3.1.45", + "wasm-feature-detect": "1.8.0" + }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, - "node_modules/@php-wasm/web-8-2": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/web-8-2/-/web-8-2-3.0.52.tgz", - "integrity": "sha512-btSMCor5I3735zudkQ0fKthfUxjx+KUgqf6ZHxjSkZ/baKXMpzVH7hTMhh1HjWWOmjQhqNBQ2KyeHzzAlm9+KQ==", + "node_modules/@php-wasm/node-8-3": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/node-8-3/-/node-8-3-3.1.45.tgz", + "integrity": "sha512-dq22w7k6zxSgRKEjFej2k2etHpWA/f6UZFQCwi0qPFTejlVRfGqJoY+6gwtF4PCCGXGD7J36XyRuSFuZz833MA==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { - "@php-wasm/universal": "3.0.52", - "ini": "4.1.2", + "@php-wasm/universal": "3.1.45", "wasm-feature-detect": "1.8.0" }, "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, - "node_modules/@php-wasm/web-8-2/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", + "node_modules/@php-wasm/node-8-4": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/node-8-4/-/node-8-4-3.1.45.tgz", + "integrity": "sha512-QElunKrFEpVa11Fdr6Afmw/gI/bCf5rxzAuXLBYfgghJP2w8sTT0M1ku1pocPEvMGeONbQgvHA06sDdKXhHEMA==", "dev": true, - "license": "ISC", + "license": "GPL-2.0-or-later", + "dependencies": { + "@php-wasm/universal": "3.1.45", + "wasm-feature-detect": "1.8.0" + }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, - "node_modules/@php-wasm/web-8-3": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/web-8-3/-/web-8-3-3.0.52.tgz", - "integrity": "sha512-ahmusrtgmi/TIsWlHCfHX0GXxI0RdeCYGzrIYxQeFH3eEchX7J5ssqImL7sPFvP6tT/bluwn9rLef0Z2hki8bg==", + "node_modules/@php-wasm/node-8-5": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/node-8-5/-/node-8-5-3.1.45.tgz", + "integrity": "sha512-FeKtaRMZorN1uRFbC6DILfv+Y9ImEMLjcpNVyT7zZ4WHPEf1yN0Q0Jo8VH9NNwCmkmiDAQN2gAIn3nKL8vsz+g==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { - "@php-wasm/universal": "3.0.52", - "ini": "4.1.2", + "@php-wasm/universal": "3.1.45", "wasm-feature-detect": "1.8.0" }, "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, - "node_modules/@php-wasm/web-8-3/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", + "node_modules/@php-wasm/progress": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/progress/-/progress-3.1.45.tgz", + "integrity": "sha512-rc/I9MSoqAPLRmrgArpWMrSq6s7R16ulrMjG3Ti5T4hfu+j2oxfBCHbrwzR57ITsgecjKZ+G9j/w+saQj9cgpQ==", "dev": true, - "license": "ISC", + "license": "GPL-2.0-or-later", + "dependencies": { + "@php-wasm/logger": "3.1.45" + }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, - "node_modules/@php-wasm/web-8-4": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/web-8-4/-/web-8-4-3.0.52.tgz", - "integrity": "sha512-/5Ah8+tIhnO4RQbQZdkwasJ1NCubKlIfOTWi1N/uQlk0OrQ2KmVj5wB4PGDeYoP41FY2Qawffa8DYf4pdypM4w==", + "node_modules/@php-wasm/scopes": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/scopes/-/scopes-3.1.45.tgz", + "integrity": "sha512-7efo3IvGLMOcUuywB40avWz1c6c7YurmRW/hM44iPlhr72x9Wpth9eHjI+Gsn+qFISmUqjW+G2KHx9BD7BTQBA==", "dev": true, "license": "GPL-2.0-or-later", - "dependencies": { - "@php-wasm/universal": "3.0.52", - "ini": "4.1.2", - "wasm-feature-detect": "1.8.0" - }, "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, - "node_modules/@php-wasm/web-8-4/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", + "node_modules/@php-wasm/stream-compression": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/stream-compression/-/stream-compression-3.1.45.tgz", + "integrity": "sha512-zLU1AGNEg1tuwm93LHrL8OcV24LyNglTg/CXV5CVZiMPpg1wfIDHJy11qqjZM8iCIJk87qYQhkKOjTnGinAVDg==", "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "license": "GPL-2.0-or-later", + "dependencies": { + "@php-wasm/util": "3.1.45" } }, - "node_modules/@php-wasm/web-8-5": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/web-8-5/-/web-8-5-3.0.52.tgz", - "integrity": "sha512-DlEhsPKFxXRaTXeuikrl8/de3Ru2putx6iWqPe8qaGNW4mKXQKjBNcwgR5NK83BzNa8ajnxDtl8tTYcTRY1iVg==", + "node_modules/@php-wasm/universal": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/universal/-/universal-3.1.45.tgz", + "integrity": "sha512-3x0TWQg6NEeO+M/oPA3rAP0hJB2gnsqwkb2sUipz0RQQXRkWEJjdrT20UVmGN/dXILDWeQg/VGxZhCktoWZGkA==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { - "@php-wasm/universal": "3.0.52", - "ini": "4.1.2", - "wasm-feature-detect": "1.8.0" + "@php-wasm/logger": "3.1.45", + "@php-wasm/progress": "3.1.45", + "@php-wasm/stream-compression": "3.1.45", + "@php-wasm/util": "3.1.45", + "ini": "4.1.2" }, "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, - "node_modules/@php-wasm/web-8-5/node_modules/ini": { + "node_modules/@php-wasm/universal/node_modules/ini": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", @@ -3981,48 +4019,41 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/@php-wasm/web-service-worker": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/web-service-worker/-/web-service-worker-3.0.52.tgz", - "integrity": "sha512-eKOLRvXexO5XyiY9wsy8DGXKOnGcovLqxhJeez2eTZ7uQ95k5oOV0Vf9w9OUkLNOWpGg4/qts6Yh4BOgEABLOw==", + "node_modules/@php-wasm/util": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/util/-/util-3.1.45.tgz", + "integrity": "sha512-czXqXd2NJWkapV/zTr3WPSPdcgyI5KN7xSUusYpgkfljSovfvHOKKrTMQtbfPXRa9+MD8LmPQt+XStKPRp76Tg==", "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@php-wasm/scopes": "3.0.52" - }, "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, - "node_modules/@php-wasm/web/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", + "node_modules/@php-wasm/web-service-worker": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/web-service-worker/-/web-service-worker-3.1.45.tgz", + "integrity": "sha512-L8spIluLVlaOZ8CnNPfJ5IEM/e1YouQ9kB8GJL+NVm27Pci/pxBE5Hi7nsmau/oQJ6JTA6rXMuDh3wyicFU0Xg==", "dev": true, - "license": "ISC", + "license": "GPL-2.0-or-later", + "dependencies": { + "@php-wasm/scopes": "3.1.45", + "@php-wasm/universal": "3.1.45" + }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, "node_modules/@php-wasm/xdebug-bridge": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/xdebug-bridge/-/xdebug-bridge-3.0.52.tgz", - "integrity": "sha512-lqVwXpjMuD4niKU3cmAiqTnTg6tk6gRqI7PLbMlmDDXJ7g59HebYkBd5NCXRCphGSj47ge44Fy/itoa0EOiluw==", + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/xdebug-bridge/-/xdebug-bridge-3.1.45.tgz", + "integrity": "sha512-InIWrSl9ULFEyIYbIK+uh2TK3N7VhQuycx3tRSaRY7YNpUGS2xxfNSt4BeJgBgUNmslKsQojSjCcmvumJW1mgg==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { - "@php-wasm/logger": "3.0.52", - "@php-wasm/node": "3.0.52", - "@php-wasm/universal": "3.0.52", - "@wp-playground/common": "3.0.52", - "express": "4.22.0", - "ini": "4.1.2", - "wasm-feature-detect": "1.8.0", - "ws": "8.18.3", + "@php-wasm/logger": "3.1.45", + "@php-wasm/universal": "3.1.45", + "ws": "8.21.0", "xml2js": "0.6.2", "yargs": "17.7.2" }, @@ -4030,21 +4061,8 @@ "xdebug-bridge": "xdebug-bridge.js" }, "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@php-wasm/xdebug-bridge/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, "node_modules/@pkgjs/parseargs": { @@ -4053,36 +4071,246 @@ "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, "optional": true, - "engines": { - "node": ">=14" - } + "engines": { + "node": ">=14" + } + }, + "node_modules/@rokoli/vue-tiny-i18n": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@rokoli/vue-tiny-i18n/-/vue-tiny-i18n-0.3.0.tgz", + "integrity": "sha512-UedVdP670KrV/lzDzDyhpKHBBIqeHLydf06xuGdLWTqJcq8hu6ZKjnnlNaoxOs+Fwu8En6fUCWo1wAcQIIVyaQ==", + "dependencies": { + "js-yaml": "^4.1.0" + }, + "peerDependencies": { + "vue": "^3.2" + } + }, + "node_modules/@rokoli/vue-tiny-i18n/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/@rokoli/vue-tiny-i18n/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==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.41.1.tgz", + "integrity": "sha512-NELNvyEWZ6R9QMkiytB4/L4zSEaBC03KIXEghptLGLZWJ6VPrL63ooZQCOnlx36aQPGhzuOMwDerC1Eb2VmrLw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.41.1.tgz", + "integrity": "sha512-DXdQe1BJ6TK47ukAoZLehRHhfKnKg9BjnQYUu9gzhI8Mwa1d2fzxA1aw2JixHVl403bwp1+/o/NhhHtxWJBgEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.41.1.tgz", + "integrity": "sha512-5afxvwszzdulsU2w8JKWwY8/sJOLPzf0e1bFuvcW5h9zsEg+RQAojdW0ux2zyYAz7R8HvvzKCjLNJhVq965U7w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.41.1.tgz", + "integrity": "sha512-egpJACny8QOdHNNMZKf8xY0Is6gIMz+tuqXlusxquWu3F833DcMwmGM7WlvCO9sB3OsPjdC4U0wHw5FabzCGZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.41.1.tgz", + "integrity": "sha512-DBVMZH5vbjgRk3r0OzgjS38z+atlupJ7xfKIDJdZZL6sM6wjfDNo64aowcLPKIx7LMQi8vybB56uh1Ftck/Atg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.41.1.tgz", + "integrity": "sha512-3FkydeohozEskBxNWEIbPfOE0aqQgB6ttTkJ159uWOFn42VLyfAiyD9UK5mhu+ItWzft60DycIN1Xdgiy8o/SA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.41.1.tgz", + "integrity": "sha512-wC53ZNDgt0pqx5xCAgNunkTzFE8GTgdZ9EwYGVcg+jEjJdZGtq9xPjDnFgfFozQI/Xm1mh+D9YlYtl+ueswNEg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.41.1.tgz", + "integrity": "sha512-jwKCca1gbZkZLhLRtsrka5N8sFAaxrGz/7wRJ8Wwvq3jug7toO21vWlViihG85ei7uJTpzbXZRcORotE+xyrLA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.41.1.tgz", + "integrity": "sha512-g0UBcNknsmmNQ8V2d/zD2P7WWfJKU0F1nu0k5pW4rvdb+BIqMm8ToluW/eeRmxCared5dD76lS04uL4UaNgpNA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.41.1.tgz", + "integrity": "sha512-XZpeGB5TKEZWzIrj7sXr+BEaSgo/ma/kCgrZgL0oo5qdB1JlTzIYQKel/RmhT6vMAvOdM2teYlAaOGJpJ9lahg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.41.1.tgz", + "integrity": "sha512-bkCfDJ4qzWfFRCNt5RVV4DOw6KEgFTUZi2r2RuYhGWC8WhCA8lCAJhDeAmrM/fdiAH54m0mA0Vk2FGRPyzI+tw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.41.1.tgz", + "integrity": "sha512-3mr3Xm+gvMX+/8EKogIZSIEF0WUu0HL9di+YWlJpO8CQBnoLAEL/roTCxuLncEdgcfJcvA4UMOf+2dnjl4Ut1A==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@rokoli/vue-tiny-i18n": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@rokoli/vue-tiny-i18n/-/vue-tiny-i18n-0.3.0.tgz", - "integrity": "sha512-UedVdP670KrV/lzDzDyhpKHBBIqeHLydf06xuGdLWTqJcq8hu6ZKjnnlNaoxOs+Fwu8En6fUCWo1wAcQIIVyaQ==", - "dependencies": { - "js-yaml": "^4.1.0" - }, - "peerDependencies": { - "vue": "^3.2" - } + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.41.1.tgz", + "integrity": "sha512-3rwCIh6MQ1LGrvKJitQjZFuQnT2wxfU+ivhNBzmxXTXPllewOF7JR1s2vMX/tWtUYFgphygxjqMl76q4aMotGw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@rokoli/vue-tiny-i18n/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.41.1.tgz", + "integrity": "sha512-LdIUOb3gvfmpkgFZuccNa2uYiqtgZAz3PTzjuM5bH3nvuy9ty6RGc/Q0+HDFrHrizJGVpjnTZ1yS5TNNjFlklw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@rokoli/vue-tiny-i18n/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==", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.41.1.tgz", + "integrity": "sha512-oIE6M8WC9ma6xYqjvPhzZYk6NbobIURvP/lEbh7FWplcMO6gn7MM2yHKA1eC/GvYwzNKK/1LYgqzdkZ8YFxR8g==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { "version": "4.41.1", @@ -4110,6 +4338,48 @@ "linux" ] }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.41.1.tgz", + "integrity": "sha512-lZkCxIrjlJlMt1dLO/FbpZbzt6J/A8p4DnqzSa4PWqPEUUUnzXLeki/iyPLfV0BmHItlYgHUqJe+3KiyydmiNQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.41.1.tgz", + "integrity": "sha512-+psFT9+pIh2iuGsxFYYa/LhS5MFKmuivRsx9iPJWNSGbh2XVEjk90fmpUEjCnILPEPJnikAU6SFDiEUyOv90Pg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.41.1.tgz", + "integrity": "sha512-Wq2zpapRYLfi4aKxf2Xff0tN+7slj2d4R87WEzqw7ZLsVvO5zwYCIuEGSZYiK41+GlwUo1HiR+GdkLEJnCKTCw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@shikijs/core": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-2.5.0.tgz", @@ -4214,9 +4484,9 @@ } }, "node_modules/@types/aws-lambda": { - "version": "8.10.160", - "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.160.tgz", - "integrity": "sha512-uoO4QVQNWFPJMh26pXtmtrRfGshPUSpMZGUyUQY20FhfHEElEBOPKgVmFs1z+kbpyBsRs2JnoOPT7++Z4GA9pA==", + "version": "8.10.162", + "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.162.tgz", + "integrity": "sha512-Fn658grtLOci1oxi1391vvDWJRKNGWRSqfxRkmN/Iy3c0tQH1USMKEXcPYHLvope+ZgTFocx9FRQJx1muBL6qw==", "dev": true, "license": "MIT" }, @@ -4366,16 +4636,6 @@ "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz", "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==" }, - "node_modules/@types/yauzl": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.1.tgz", - "integrity": "sha512-CHzgNU3qYBnp/O4S3yv2tXPlvMTq0YWSTVg2/JYLqWZGHwwgJGAwd00poay/11asPq8wLFwHzubyInqHIFmmiw==", - "dev": true, - "optional": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@ungap/structured-clone": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", @@ -4396,13 +4656,13 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.30.tgz", - "integrity": "sha512-s3DfdZkcu/qExZ+td75015ljzHc6vE+30cFMGRPROYjqkroYI5NV2X1yAMX9UeyBNWB9MxCfPcsjpLS11nzkkw==", + "version": "3.5.40", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.40.tgz", + "integrity": "sha512-39E8IgOhTbVDnoJFMKc2DvYnypcZwUqgUhQkccva/0m6FUwtIKSGV7n1hpVmYcFaoRAwf9pBcwnKlCEsN63ZEQ==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.0", - "@vue/shared": "3.5.30", + "@babel/parser": "^7.29.7", + "@vue/shared": "3.5.40", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" @@ -4421,40 +4681,40 @@ } }, "node_modules/@vue/compiler-dom": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.30.tgz", - "integrity": "sha512-eCFYESUEVYHhiMuK4SQTldO3RYxyMR/UQL4KdGD1Yrkfdx4m/HYuZ9jSfPdA+nWJY34VWndiYdW/wZXyiPEB9g==", + "version": "3.5.40", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.40.tgz", + "integrity": "sha512-pwkx4vqlqOspFstrcmzwkKLePVMD3PT65imRzLhanU2V1Fj4K13g6OXjanOyzw3aTAuRk84BOmY8f3rEHqPaVA==", "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.5.30", - "@vue/shared": "3.5.30" + "@vue/compiler-core": "3.5.40", + "@vue/shared": "3.5.40" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.30.tgz", - "integrity": "sha512-LqmFPDn89dtU9vI3wHJnwaV6GfTRD87AjWpTWpyrdVOObVtjIuSeZr181z5C4PmVx/V3j2p+0f7edFKGRMpQ5A==", + "version": "3.5.40", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.40.tgz", + "integrity": "sha512-gIf497P4kpuALcvs5n3AEg1Vdn0pSY4XbjASIfHNYF1/MP3T2Mf2STERTubysBxCRxzJGJYtF/O7vwJrxFB3Vw==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.0", - "@vue/compiler-core": "3.5.30", - "@vue/compiler-dom": "3.5.30", - "@vue/compiler-ssr": "3.5.30", - "@vue/shared": "3.5.30", + "@babel/parser": "^7.29.7", + "@vue/compiler-core": "3.5.40", + "@vue/compiler-dom": "3.5.40", + "@vue/compiler-ssr": "3.5.40", + "@vue/shared": "3.5.40", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", - "postcss": "^8.5.8", + "postcss": "^8.5.19", "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-ssr": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.30.tgz", - "integrity": "sha512-NsYK6OMTnx109PSL2IAyf62JP6EUdk4Dmj6AkWcJGBvN0dQoMYtVekAmdqgTtWQgEJo+Okstbf/1p7qZr5H+bA==", + "version": "3.5.40", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.40.tgz", + "integrity": "sha512-rrE5xiXG663+vHCHa3J9p2z5OcBRjXmoqenprJxAFQxg5pSshzeBiCE6pu46axapRJ2Adk0YDA2BRZVjiHXnhg==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.30", - "@vue/shared": "3.5.30" + "@vue/compiler-dom": "3.5.40", + "@vue/shared": "3.5.40" } }, "node_modules/@vue/devtools-api": { @@ -4491,53 +4751,51 @@ } }, "node_modules/@vue/reactivity": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.30.tgz", - "integrity": "sha512-179YNgKATuwj9gB+66snskRDOitDiuOZqkYia7mHKJaidOMo/WJxHKF8DuGc4V4XbYTJANlfEKb0yxTQotnx4Q==", + "version": "3.5.40", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.40.tgz", + "integrity": "sha512-B7ot9UlUZOi1zbq61/LvE88ZLTV8IlajTdiZTAEiDQgrnIMIZoPr9kGw0Zw46ObW62O9+H/Be3kMbfb7kYPQZA==", "license": "MIT", "dependencies": { - "@vue/shared": "3.5.30" + "@vue/shared": "3.5.40" } }, "node_modules/@vue/runtime-core": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.30.tgz", - "integrity": "sha512-e0Z+8PQsUTdwV8TtEsLzUM7SzC7lQwYKePydb7K2ZnmS6jjND+WJXkmmfh/swYzRyfP1EY3fpdesyYoymCzYfg==", + "version": "3.5.40", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.40.tgz", + "integrity": "sha512-KAZLweuZ6uUJPK1PMSQPgBU5gCjgrrfjUhSglmU9NhH+Zjepa8cnwSydPWDWHDwOgY4g3VcZ+PljbiHlURNCbw==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.30", - "@vue/shared": "3.5.30" + "@vue/reactivity": "3.5.40", + "@vue/shared": "3.5.40" } }, "node_modules/@vue/runtime-dom": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.30.tgz", - "integrity": "sha512-2UIGakjU4WSQ0T4iwDEW0W7vQj6n7AFn7taqZ9Cvm0Q/RA2FFOziLESrDL4GmtI1wV3jXg5nMoJSYO66egDUBw==", + "version": "3.5.40", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.40.tgz", + "integrity": "sha512-ZfrX8ssZQds900L9pr8AuK05ddnMsR4MPMZr8cPN9GoqoPWcXLhjvvbIA2SMv+7a97sJ1vv9pj/zxK0Cq/eEFQ==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.30", - "@vue/runtime-core": "3.5.30", - "@vue/shared": "3.5.30", + "@vue/reactivity": "3.5.40", + "@vue/runtime-core": "3.5.40", + "@vue/shared": "3.5.40", "csstype": "^3.2.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.30.tgz", - "integrity": "sha512-v+R34icapydRwbZRD0sXwtHqrQJv38JuMB4JxbOxd8NEpGLny7cncMp53W9UH/zo4j8eDHjQ1dEJXwzFQknjtQ==", + "version": "3.5.40", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.40.tgz", + "integrity": "sha512-XNJym9WpevhTVt1HuwOrCRJ5Q+9z4BjTMrDtjTrvx74SmUll8spNTw6whWJa9mEkO4PKn5TihI/bm/8ds2QVJw==", "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.5.30", - "@vue/shared": "3.5.30" - }, - "peerDependencies": { - "vue": "3.5.30" + "@vue/compiler-ssr": "3.5.40", + "@vue/runtime-dom": "3.5.40", + "@vue/shared": "3.5.40" } }, "node_modules/@vue/shared": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.30.tgz", - "integrity": "sha512-YXgQ7JjaO18NeK2K9VTbDHaFy62WrObMa6XERNfNOkAhD1F1oDSf3ZJ7K6GqabZ0BvSDHajp8qfS5Sa2I9n8uQ==", + "version": "3.5.40", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.40.tgz", + "integrity": "sha512-WxnBtruIqOoV3rA4jeKDWzrYI5h7Cp4+pjwDi8kWGHz+IslhiN+wguLVVhtv2l8VoU02rzDCVfDjgCl1lNpZVg==", "license": "MIT" }, "node_modules/@vueuse/core": { @@ -4732,24 +4990,24 @@ } }, "node_modules/@wordpress/env": { - "version": "11.3.0", - "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-11.3.0.tgz", - "integrity": "sha512-LxJGteosQmrOV8JEqEIeh3N8/poplFexJjW2M0b+GpKfd7Njt6zoEZhONo01YIR01gk2d21HPBApBw5goa84Xg==", + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-11.11.0.tgz", + "integrity": "sha512-E4Riaan41uAcm70FFTD78Z1qtObQJwRlIyXdsr04X+mrg8XkBuHSqM1iSvgqnOpVzUuF9EYANYKF0CTm9tKW5w==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { "@inquirer/prompts": "^7.2.0", "@wp-playground/cli": "^3.0.48", - "chalk": "^4.0.0", + "adm-zip": "^0.5.9", + "chalk": "^4.1.1", "copy-dir": "^1.3.0", "cross-spawn": "^7.0.6", "docker-compose": "^0.24.3", - "extract-zip": "^1.6.7", "got": "^11.8.5", - "js-yaml": "^3.13.1", + "js-yaml": "^3.15.0", "ora": "^4.0.2", "rimraf": "^5.0.10", - "simple-git": "^3.5.0", + "simple-git": "^3.24.0", "yargs": "^17.3.0" }, "bin": { @@ -4878,6 +5136,20 @@ "@pkgjs/parseargs": "^0.11.0" } }, + "node_modules/@wordpress/env/node_modules/js-yaml": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.0.tgz", + "integrity": "sha512-ttBQIIQPDeLjpPOohtUdXuXUVoA2uIB6fEH9HyJ7234s5mBJ5wTx20njxplLZQgLaOfpmPQA7X2t5AX6tIPbog==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/@wordpress/env/node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", @@ -4930,384 +5202,145 @@ } }, "node_modules/@wordpress/env/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@wp-playground/blueprints": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@wp-playground/blueprints/-/blueprints-3.0.52.tgz", - "integrity": "sha512-WQ11urt2O6YItvwwwOYYFqw5wqDPwc5qgaYDsI8cp3hQqH/8bn6xIAwPR55ITNiZYhxl39+aOW1fqRzmymCkyA==", - "dev": true, - "dependencies": { - "@php-wasm/logger": "3.0.52", - "@php-wasm/node": "3.0.52", - "@php-wasm/node-polyfills": "3.0.52", - "@php-wasm/progress": "3.0.52", - "@php-wasm/scopes": "3.0.52", - "@php-wasm/stream-compression": "3.0.52", - "@php-wasm/universal": "3.0.52", - "@php-wasm/util": "3.0.52", - "@php-wasm/web-service-worker": "3.0.52", - "@wp-playground/common": "3.0.52", - "@wp-playground/storage": "3.0.52", - "@wp-playground/wordpress": "3.0.52", - "@zip.js/zip.js": "2.7.57", - "ajv": "8.12.0", - "async-lock": "1.4.1", - "clean-git-ref": "2.0.1", - "crc-32": "1.2.2", - "diff3": "0.0.4", - "express": "4.22.0", - "ignore": "5.3.2", - "ini": "4.1.2", - "minimisted": "2.0.1", - "octokit": "3.1.2", - "pako": "1.0.10", - "pify": "2.3.0", - "readable-stream": "3.6.2", - "selfsigned": "5.5.0", - "sha.js": "2.4.12", - "simple-get": "4.0.1", - "wasm-feature-detect": "1.8.0", - "ws": "8.18.3", - "yargs": "17.7.2" - }, - "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@wp-playground/blueprints/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@wp-playground/blueprints/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@wp-playground/cli": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@wp-playground/cli/-/cli-3.0.52.tgz", - "integrity": "sha512-IU3JnEetWQUyewnB3a8I9o3r+9D2nEqoisQje6Fs5kO4QfVgCluiP4ek6HmKEd0pBSaby9Qt2OAdRrKaPQBwIQ==", - "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@php-wasm/cli-util": "3.0.52", - "@php-wasm/logger": "3.0.52", - "@php-wasm/node": "3.0.52", - "@php-wasm/progress": "3.0.52", - "@php-wasm/universal": "3.0.52", - "@php-wasm/util": "3.0.52", - "@php-wasm/xdebug-bridge": "3.0.52", - "@wp-playground/blueprints": "3.0.52", - "@wp-playground/common": "3.0.52", - "@wp-playground/storage": "3.0.52", - "@wp-playground/tools": "3.0.52", - "@wp-playground/wordpress": "3.0.52", - "@zip.js/zip.js": "2.7.57", - "ajv": "8.12.0", - "async-lock": "1.4.1", - "clean-git-ref": "2.0.1", - "crc-32": "1.2.2", - "diff3": "0.0.4", - "express": "4.22.0", - "fast-xml-parser": "^5.3.4", - "fs-extra": "11.1.1", - "ignore": "5.3.2", - "ini": "4.1.2", - "jsonc-parser": "3.3.1", - "minimisted": "2.0.1", - "octokit": "3.1.2", - "pako": "1.0.10", - "pify": "2.3.0", - "ps-man": "1.1.8", - "readable-stream": "3.6.2", - "selfsigned": "5.5.0", - "sha.js": "2.4.12", - "simple-get": "4.0.1", - "tmp-promise": "3.0.3", - "wasm-feature-detect": "1.8.0", - "ws": "8.18.3", - "xml2js": "0.6.2", - "yargs": "17.7.2" - }, - "bin": { - "wp-playground-cli": "wp-playground.js" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@wp-playground/cli/node_modules/fs-extra": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", - "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, - "node_modules/@wp-playground/cli/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@wp-playground/cli/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@wp-playground/common": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@wp-playground/common/-/common-3.0.52.tgz", - "integrity": "sha512-umfP5lCzjAWqJ3woSrlff+SGDal5y4QHftSk/w5L8SuwlZ0Rq8Q9X5CC2jA0adl8dfyb8auJPqpDbTf4+wWP8A==", - "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@php-wasm/universal": "3.0.52", - "@php-wasm/util": "3.0.52", - "ini": "4.1.2" - }, - "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@wp-playground/common/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@wp-playground/storage": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@wp-playground/storage/-/storage-3.0.52.tgz", - "integrity": "sha512-/oZeM5GIELessrzhLFJJscKXtLn34FT2IgqKLg4Vi2uqQ1gdYWx9A24tnLs59MeHa8Mvu0jEAPcAd6AM/ze1yQ==", - "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@php-wasm/stream-compression": "3.0.52", - "@php-wasm/universal": "3.0.52", - "@php-wasm/util": "3.0.52", - "@php-wasm/web": "3.0.52", - "@zip.js/zip.js": "2.7.57", - "async-lock": "^1.4.1", - "clean-git-ref": "^2.0.1", - "crc-32": "^1.2.0", - "diff3": "0.0.3", - "express": "4.22.0", - "ignore": "^5.1.4", - "ini": "4.1.2", - "minimisted": "^2.0.0", - "octokit": "3.1.2", - "pako": "^1.0.10", - "pify": "^4.0.1", - "readable-stream": "^3.4.0", - "selfsigned": "5.5.0", - "sha.js": "^2.4.9", - "simple-get": "^4.0.1", - "wasm-feature-detect": "1.8.0", - "ws": "8.18.3", - "yargs": "17.7.2" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@wp-playground/storage/node_modules/diff3": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/diff3/-/diff3-0.0.3.tgz", - "integrity": "sha512-iSq8ngPOt0K53A6eVr4d5Kn6GNrM2nQZtC740pzIriHtn4pOQ2lyzEXQMBeVcWERN0ye7fhBsk9PbLLQOnUx/g==", - "dev": true, - "license": "MIT" - }, - "node_modules/@wp-playground/storage/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@wp-playground/storage/node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/@wp-playground/storage/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "node_modules/@wp-playground/blueprints": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@wp-playground/blueprints/-/blueprints-3.1.45.tgz", + "integrity": "sha512-q7jEN5w6dgwpzk26mkSGLLPEsTQsRfily0wPolAwueyhq2bnY7Nil7r1k+JHTR2XpTSg3Y3rFyp3j1biOpbsDA==", "dev": true, - "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "@php-wasm/logger": "3.1.45", + "@php-wasm/progress": "3.1.45", + "@php-wasm/stream-compression": "3.1.45", + "@php-wasm/universal": "3.1.45", + "@php-wasm/util": "3.1.45", + "@php-wasm/web-service-worker": "3.1.45", + "@wp-playground/common": "3.1.45", + "@wp-playground/storage": "3.1.45", + "@wp-playground/wordpress": "3.1.45", + "ajv": "8.18.0" }, "engines": { - "node": ">= 6" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, - "node_modules/@wp-playground/tools": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@wp-playground/tools/-/tools-3.0.52.tgz", - "integrity": "sha512-uBCbO5rztC1cObHy+ehlDGXiFeZOuqHMCYgZJSUX4q7oqXa+AMua1IMc33AVkfSVjPFnp3f+/oR24hM2nYAWCg==", + "node_modules/@wp-playground/cli": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@wp-playground/cli/-/cli-3.1.45.tgz", + "integrity": "sha512-9cSDXOJoSdZSVrNBOraLlkiBMnvxy0EyaUrkr/8kBkNhWgNv2WhoPxMY25B0eh8nocH2mLVFHg9s4thuFghhug==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { - "@wp-playground/blueprints": "3.0.52", - "@zip.js/zip.js": "2.7.57", - "ajv": "8.12.0", - "async-lock": "1.4.1", - "clean-git-ref": "2.0.1", - "crc-32": "1.2.2", - "diff3": "0.0.4", - "express": "4.22.0", - "ignore": "5.3.2", - "ini": "4.1.2", - "minimisted": "2.0.1", - "octokit": "3.1.2", - "pako": "1.0.10", - "pify": "2.3.0", - "readable-stream": "3.6.2", - "selfsigned": "5.5.0", - "sha.js": "2.4.12", - "simple-get": "4.0.1", + "@php-wasm/cli-util": "3.1.45", + "@php-wasm/logger": "3.1.45", + "@php-wasm/node": "3.1.45", + "@php-wasm/progress": "3.1.45", + "@php-wasm/universal": "3.1.45", + "@php-wasm/util": "3.1.45", + "@php-wasm/xdebug-bridge": "3.1.45", + "@wp-playground/blueprints": "3.1.45", + "@wp-playground/common": "3.1.45", + "@wp-playground/storage": "3.1.45", + "@wp-playground/tools": "3.1.45", + "@wp-playground/wordpress": "3.1.45", + "express": "4.22.2", + "fs-extra": "11.1.1", + "tmp-promise": "3.0.3", "wasm-feature-detect": "1.8.0", - "ws": "8.18.3", "yargs": "17.7.2" }, - "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" + "bin": { + "wp-playground-cli": "wp-playground.js" } }, - "node_modules/@wp-playground/tools/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", + "node_modules/@wp-playground/cli/node_modules/fs-extra": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", + "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", "dev": true, - "license": "ISC", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=14.14" } }, - "node_modules/@wp-playground/tools/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "node_modules/@wp-playground/common": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@wp-playground/common/-/common-3.1.45.tgz", + "integrity": "sha512-dhVGdPqp4D0RhodW9sxdI3gdKPI98ue0oyXX4AeL4toLvjzKF1nz3AwniojsuHbJr0RV0QhA/Z2rYcTjynLD8A==", "dev": true, - "license": "MIT", + "license": "GPL-2.0-or-later", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "@php-wasm/universal": "3.1.45", + "@php-wasm/util": "3.1.45" }, "engines": { - "node": ">= 6" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, - "node_modules/@wp-playground/wordpress": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@wp-playground/wordpress/-/wordpress-3.0.52.tgz", - "integrity": "sha512-P37YCxJuDSBCi0JIL4mkYUJsCSW1GrnL2LWTgups/NKWf1MCODEhmCSFfixfbMb7BFOvlC6Tb8RXw+O2dG1Ouw==", + "node_modules/@wp-playground/storage": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@wp-playground/storage/-/storage-3.1.45.tgz", + "integrity": "sha512-c9iWgHHhwEElroXqWBi8B7rSsvAbSYjCDA1m5zTmg+jpscbT8zLrIohJ3WANbWljeSxG4sWA87PLqARdchyl3A==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { - "@php-wasm/logger": "3.0.52", - "@php-wasm/node": "3.0.52", - "@php-wasm/universal": "3.0.52", - "@php-wasm/util": "3.0.52", - "@wp-playground/common": "3.0.52", - "express": "4.22.0", - "ini": "4.1.2", - "wasm-feature-detect": "1.8.0", - "ws": "8.18.3", - "yargs": "17.7.2" + "@php-wasm/stream-compression": "3.1.45", + "@php-wasm/universal": "3.1.45", + "@php-wasm/util": "3.1.45", + "@zip.js/zip.js": "2.7.57", + "isomorphic-git": "1.37.6", + "octokit": "3.1.2", + "pako": "^1.0.10", + "sha.js": "2.4.12" + } + }, + "node_modules/@wp-playground/tools": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@wp-playground/tools/-/tools-3.1.45.tgz", + "integrity": "sha512-nhGuCsVgd0VIe+nQgrKKsVXCu2XHHSnj7+GiH4qIThYUpXLMZo/s+w1bI0ANGOCgpUTOv89Q2JOFPrn37+b3tA==", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@wp-playground/blueprints": "3.1.45" }, "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, - "node_modules/@wp-playground/wordpress/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", + "node_modules/@wp-playground/wordpress": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@wp-playground/wordpress/-/wordpress-3.1.45.tgz", + "integrity": "sha512-kQqx7m4oKRnSmTxiwdwVnUGetJINHVULMURff2+JZ4EGLqAUVscyCQ4YvQMnIho6gASyzt8TYLr3GqxU+1n6AA==", "dev": true, - "license": "ISC", + "license": "GPL-2.0-or-later", + "dependencies": { + "@php-wasm/logger": "3.1.45", + "@php-wasm/universal": "3.1.45", + "@php-wasm/util": "3.1.45", + "@wp-playground/common": "3.1.45", + "zstddec": "^0.2.0" + }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, "node_modules/@zip.js/zip.js": { @@ -5328,6 +5361,19 @@ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -5342,6 +5388,16 @@ "node": ">= 0.6" } }, + "node_modules/adm-zip": { + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.17.tgz", + "integrity": "sha512-+Ut8d9LLqwEvHHJl1+PIHqoyDxFgVN847JTVM3Izi3xHDWPE4UtzzXysMZQs64DMcrJfBeS/uoEP4AD3HQHnQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0" + } + }, "node_modules/aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -5356,16 +5412,16 @@ } }, "node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "dev": true, "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -5396,15 +5452,6 @@ "node": ">= 14.0.0" } }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -5454,6 +5501,19 @@ "node": ">= 8" } }, + "node_modules/anynum": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/anynum/-/anynum-1.0.1.tgz", + "integrity": "sha512-N6//FLET/tXYNM/F6ABca1oH6fWB+KlTt909Le28WMDBk8oaT4vY17DCrwg2MvmuqUKt3Ni4N5dGJ/EoBgcO6A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, "node_modules/append-transform": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", @@ -5577,21 +5637,6 @@ "safer-buffer": "~2.1.0" } }, - "node_modules/asn1js": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.7.tgz", - "integrity": "sha512-uLvq6KJu04qoQM6gvBfKFjlh6Gl0vOKQuR5cJMDHQkmwfMOQeN3F3SHCv9SNYSL+CRoHvOGFfllDlVz03GQjvQ==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "pvtsutils": "^1.3.6", - "pvutils": "^1.1.3", - "tslib": "^2.8.1" - }, - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", @@ -5611,15 +5656,6 @@ "node": ">=0.10.0" } }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/async": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", @@ -5918,9 +5954,9 @@ } }, "node_modules/body-parser": { - "version": "1.20.4", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", - "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", + "version": "1.20.6", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.6.tgz", + "integrity": "sha512-p5tAzS57i5MV9fZFDj9LeIiTZEufbSe2eDozP+ElheSUq1m74CRq1jI4mYNDdVs9vQztXFLuk/Gd6BWTdwRJ5g==", "dev": true, "license": "MIT", "dependencies": { @@ -5932,7 +5968,7 @@ "http-errors": "~2.0.1", "iconv-lite": "~0.4.24", "on-finished": "~2.4.1", - "qs": "~6.14.0", + "qs": "~6.15.1", "raw-body": "~2.5.3", "type-is": "~1.6.18", "unpipe": "~1.0.0" @@ -6092,15 +6128,6 @@ "ieee754": "^1.1.13" } }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", @@ -6120,16 +6147,6 @@ "integrity": "sha512-/x68VkHLeTl3/Ll8IvxdwzhrT+IyKc52e/oyHhA2RwqPqswSnjVbSddfPRwAsJtbilMAPSRWwAlpxdYsSWOTKQ==", "dev": true }, - "node_modules/bytestreamjs": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/bytestreamjs/-/bytestreamjs-2.0.1.tgz", - "integrity": "sha512-U1Z/ob71V/bXfVABvNr/Kumf5VyeQRBEm6Txb0PQ6S7V5GpBM3w4Cbqz/xPDicR5tN0uvDifng8C+5qECeGwyQ==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/cache-base": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", @@ -6202,15 +6219,15 @@ } }, "node_modules/call-bind": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", - "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", + "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.0", - "es-define-property": "^1.0.0", - "get-intrinsic": "^1.2.4", + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", "set-function-length": "^1.2.2" }, "engines": { @@ -6490,21 +6507,68 @@ } }, "node_modules/cli-truncate": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", - "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.2.0.tgz", + "integrity": "sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==", "dev": true, + "license": "MIT", "dependencies": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" + "slice-ansi": "^8.0.0", + "string-width": "^8.2.0" }, "engines": { - "node": ">=8" + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/cli-truncate/node_modules/string-width": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.1.tgz", + "integrity": "sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" + }, + "engines": { + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/cli-truncate/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/cli-width": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", @@ -6590,7 +6654,8 @@ "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/colors": { "version": "1.1.2", @@ -6667,21 +6732,6 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, - "node_modules/concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "engines": [ - "node >= 0.8" - ], - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, "node_modules/console-browserify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", @@ -6704,27 +6754,6 @@ "node": ">= 0.6" } }, - "node_modules/content-disposition/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/content-type": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", @@ -6849,14 +6878,14 @@ "license": "MIT" }, "node_modules/cypress": { - "version": "15.13.1", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-15.13.1.tgz", - "integrity": "sha512-jLkgo75zlwo7PhXp0XJot+zIfFSDzN1SvTml6Xf3ETM1XHRWnH3Q4LAR3orCo/BsnxPnhjG3m5HYSvn9DAtwBg==", + "version": "15.18.1", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-15.18.1.tgz", + "integrity": "sha512-JtkTVtUE2lvLYgZCaug+Uai0H9IqsJirlBO49c87QwG0bJUGvAUVBz1EJve0b0oaYP244Ew9M0BkrHpcqkYxmw==", "dev": true, "hasInstallScript": true, "license": "MIT", "dependencies": { - "@cypress/request": "^3.0.10", + "@cypress/request": "^4.0.0", "@cypress/xvfb": "^1.2.4", "@types/sinonjs__fake-timers": "8.1.1", "@types/sizzle": "^2.3.2", @@ -6865,25 +6894,21 @@ "blob-util": "^2.0.2", "bluebird": "^3.7.2", "buffer": "^5.7.1", - "cachedir": "^2.3.0", + "cachedir": "^2.4.0", "chalk": "^4.1.0", "ci-info": "^4.1.0", - "cli-cursor": "^3.1.0", "cli-table3": "0.6.1", "commander": "^6.2.1", "common-tags": "^1.8.0", "dayjs": "^1.10.4", "debug": "^4.3.4", - "enquirer": "^2.3.6", "eventemitter2": "6.4.7", "execa": "4.1.0", "executable": "^4.1.1", - "extract-zip": "2.0.1", - "figures": "^3.2.0", "fs-extra": "^9.1.0", "hasha": "5.2.2", "is-installed-globally": "~0.4.0", - "listr2": "^3.8.3", + "listr2": "^9.0.5", "lodash": "^4.17.23", "log-symbols": "^4.0.0", "minimist": "^1.2.8", @@ -6898,7 +6923,7 @@ "tree-kill": "1.2.2", "tslib": "1.14.1", "untildify": "^4.0.0", - "yauzl": "^2.10.0" + "yauzl": "^3.3.1" }, "bin": { "cypress": "bin/cypress" @@ -6968,26 +6993,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/cypress/node_modules/extract-zip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - }, - "bin": { - "extract-zip": "cli.js" - }, - "engines": { - "node": ">= 10.17.0" - }, - "optionalDependencies": { - "@types/yauzl": "^2.9.1" - } - }, "node_modules/cypress/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -7035,6 +7040,19 @@ "dev": true, "license": "0BSD" }, + "node_modules/cypress/node_modules/yauzl": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.4.0.tgz", + "integrity": "sha512-jIH9yLR9wqr0wOS0TpBvo/g/2UgZH5qePVbjgRliiF0BYvOZyaBknKsF+x9Iht0O6sqgnB93rCICdOZFecJuDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -7344,9 +7362,9 @@ } }, "node_modules/diff3": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/diff3/-/diff3-0.0.4.tgz", - "integrity": "sha512-f1rQ7jXDn/3i37hdwRk9ohqcvLRH3+gEIgmA6qEM280WUOh7cOr3GXV8Jm5sPwUs46Nzl48SE8YNLGJoaLuodg==", + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/diff3/-/diff3-0.0.3.tgz", + "integrity": "sha512-iSq8ngPOt0K53A6eVr4d5Kn6GNrM2nQZtC740pzIriHtn4pOQ2lyzEXQMBeVcWERN0ye7fhBsk9PbLLQOnUx/g==", "dev": true, "license": "MIT" }, @@ -7618,25 +7636,25 @@ "once": "^1.4.0" } }, - "node_modules/enquirer": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", - "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", - "dev": true, - "dependencies": { - "ansi-colors": "^4.1.1", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8.6" - } - }, "node_modules/entities": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", "integrity": "sha512-LbLqfXgJMmy81t+7c14mnulFHJ170cM6E+0vMXR9k/ZiZwgX8i5pNgjTCX3SO4VeUsFLV+8InixoretwU+MjBQ==", "dev": true }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/error": { "version": "7.2.1", "resolved": "https://registry.npmjs.org/error/-/error-7.2.1.tgz", @@ -7802,12 +7820,39 @@ "node": ">= 0.6" } }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/eventemitter2": { "version": "6.4.7", "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.7.tgz", "integrity": "sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==", "dev": true }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, "node_modules/events-to-array": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/events-to-array/-/events-to-array-1.1.2.tgz", @@ -7928,15 +7973,15 @@ } }, "node_modules/express": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/express/-/express-4.22.0.tgz", - "integrity": "sha512-c2iPh3xp5vvCLgaHK03+mWLFPhox7j1LwyxcZwFVApEv5i0X+IjPpbT50SJJwwLpdBVfp45AkK/v+AFgv/XlfQ==", + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.2.tgz", + "integrity": "sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q==", "dev": true, "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "~1.20.3", + "body-parser": "~1.20.5", "content-disposition": "~0.5.4", "content-type": "~1.0.4", "cookie": "~0.7.1", @@ -7955,7 +8000,7 @@ "parseurl": "~1.3.3", "path-to-regexp": "~0.1.12", "proxy-addr": "~2.0.7", - "qs": "~6.14.0", + "qs": "~6.15.1", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "~0.19.0", @@ -7991,27 +8036,6 @@ "dev": true, "license": "MIT" }, - "node_modules/express/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -8124,36 +8148,6 @@ "node": ">=0.10.0" } }, - "node_modules/extract-zip": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz", - "integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==", - "dev": true, - "dependencies": { - "concat-stream": "^1.6.2", - "debug": "^2.6.9", - "mkdirp": "^0.5.4", - "yauzl": "^2.10.0" - }, - "bin": { - "extract-zip": "cli.js" - } - }, - "node_modules/extract-zip/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/extract-zip/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, "node_modules/extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", @@ -8171,10 +8165,44 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-uri": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.4.tgz", + "integrity": "sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fast-xml-builder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.3.0.tgz", + "integrity": "sha512-F74cZEdCvuw9P41GAC3rod4X04jjWGM1JPEv/GWSqFTWLsdyMSBMBMlm9Hk3GLBgLBbdBNY8yee0pQh2RBVESQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "path-expression-matcher": "^1.6.2", + "xml-naming": "^0.3.0" + } + }, "node_modules/fast-xml-parser": { - "version": "5.3.6", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.3.6.tgz", - "integrity": "sha512-QNI3sAvSvaOiaMl8FYU4trnEzCwiRr8XMWgAHzlrWpTSj+QaCSvOf1h82OEP1s4hiAXhnbXSyFWCf4ldZzZRVA==", + "version": "5.10.1", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.10.1.tgz", + "integrity": "sha512-IEMIf7298kXuZSRFoGfMYrl7is8LpavODgbNz1cwIudv7KwVFnuU+UsMporfq6PD6aXSlawZlARiA3UywCTfMw==", "dev": true, "funding": [ { @@ -8184,7 +8212,12 @@ ], "license": "MIT", "dependencies": { - "strnum": "^2.1.2" + "@nodable/entities": "^3.0.0", + "fast-xml-builder": "^1.2.0", + "is-unsafe": "^2.0.0", + "path-expression-matcher": "^1.6.2", + "strnum": "^2.4.1", + "xml-naming": "^0.3.0" }, "bin": { "fxparser": "src/cli/cli.js" @@ -8202,15 +8235,6 @@ "node": ">=0.4.0" } }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "dev": true, - "dependencies": { - "pend": "~1.2.0" - } - }, "node_modules/feiertagejs": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/feiertagejs/-/feiertagejs-1.5.1.tgz", @@ -8539,15 +8563,15 @@ "integrity": "sha512-kSxoARUDn4F2RPXX48UXnaFKwVU7Ivd/6qpzZL29MCDmr9sTvybv4gFCp+qaI4fM9m0z9fgz/yJvi56GAz+BZg==", "dev": true }, - "node_modules/fs-ext": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fs-ext/-/fs-ext-2.1.1.tgz", - "integrity": "sha512-/TrISPOFhCkbgIRWK9lzscRzwPCu0PqtCcvMc9jsHKBgZGoqA0VzhspVht5Zu8lxaXjIYIBWILHpRotYkCCcQA==", + "node_modules/fs-ext-extra-prebuilt": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/fs-ext-extra-prebuilt/-/fs-ext-extra-prebuilt-2.2.7.tgz", + "integrity": "sha512-Q7rayYRBDIvDF01HWOwSSjoaP+05N1g+o3BXL1Zf8Frw2JkjSmi4EtvCBITuW30l6hB2m2TW1pehdh8wyU/+gw==", "dev": true, "hasInstallScript": true, - "optional": true, + "license": "MIT", "dependencies": { - "nan": "^2.21.0" + "nan": "^2.24.0" }, "engines": { "node": ">= 8.0.0" @@ -8574,6 +8598,21 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -8620,6 +8659,19 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-east-asian-width": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz", + "integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -8897,24 +8949,25 @@ "dev": true }, "node_modules/grunt": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.6.1.tgz", - "integrity": "sha512-/ABUy3gYWu5iBmrUSRBP97JLpQUm0GgVveDCp6t3yRNIoltIYw7rEj3g5y1o2PGPR2vfTRGa7WC/LZHLTXnEzA==", + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.6.2.tgz", + "integrity": "sha512-bUzh5nA/P5L66ihXTDP6J5BGnMB/8lXJXejYWSbH4Y4TvWM9t2S39sggQDYYQlx06cYcCsmu63HMYHGCIzUVfg==", "dev": true, + "license": "MIT", "dependencies": { "dateformat": "~4.6.2", "eventemitter2": "~0.4.13", "exit": "~0.1.2", "findup-sync": "~5.0.0", "glob": "~7.1.6", - "grunt-cli": "~1.4.3", + "grunt-cli": "^1.4.3", "grunt-known-options": "~2.0.0", "grunt-legacy-log": "~3.0.0", "grunt-legacy-util": "~2.0.1", "iconv-lite": "~0.6.3", "js-yaml": "~3.14.0", - "minimatch": "~3.0.4", - "nopt": "~3.0.6" + "minimatch": "^3.1.5", + "nopt": "^5.0.0" }, "bin": { "grunt": "bin/grunt" @@ -8955,21 +9008,6 @@ "node": ">=10" } }, - "node_modules/grunt-cli/node_modules/nopt": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", - "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "dev": true, - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/grunt-contrib-clean": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/grunt-contrib-clean/-/grunt-contrib-clean-2.0.1.tgz", @@ -9525,62 +9563,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/grunt/node_modules/grunt-cli": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.4.3.tgz", - "integrity": "sha512-9Dtx/AhVeB4LYzsViCjUQkd0Kw0McN2gYpdmGYKtE2a5Yt7v1Q+HYZVWhqXc/kGnxlMtqKDxSwotiGeFmkrCoQ==", - "dev": true, - "dependencies": { - "grunt-known-options": "~2.0.0", - "interpret": "~1.1.0", - "liftup": "~3.0.1", - "nopt": "~4.0.1", - "v8flags": "~3.2.0" - }, - "bin": { - "grunt": "bin/grunt" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/grunt/node_modules/grunt-cli/node_modules/nopt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", - "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", - "dev": true, - "dependencies": { - "abbrev": "1", - "osenv": "^0.1.4" - }, - "bin": { - "nopt": "bin/nopt.js" - } - }, - "node_modules/grunt/node_modules/minimatch": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", - "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/grunt/node_modules/v8flags": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", - "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", - "dev": true, - "dependencies": { - "homedir-polyfill": "^1.0.1" - }, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/gzip-size": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz", @@ -10011,10 +9993,11 @@ } }, "node_modules/immutable": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.0.3.tgz", - "integrity": "sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==", - "dev": true + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.5.tgz", + "integrity": "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==", + "dev": true, + "license": "MIT" }, "node_modules/imurmurhash": { "version": "0.1.4", @@ -10379,6 +10362,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-unsafe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-unsafe/-/is-unsafe-2.0.0.tgz", + "integrity": "sha512-2LdV822R+wmI86unXA93WCFpL6g+av8ynWk0nrHyJqGop5VoocYsSLFgN8jrfalT6iGeLNM4KXuVSsULP53kEA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, "node_modules/is-what": { "version": "4.1.16", "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz", @@ -10421,6 +10417,42 @@ "node": ">=0.10.0" } }, + "node_modules/isomorphic-git": { + "version": "1.37.6", + "resolved": "https://registry.npmjs.org/isomorphic-git/-/isomorphic-git-1.37.6.tgz", + "integrity": "sha512-qr1NFCPsVTZ6YGqTXw0CzamnsHyH9QQ1OTEfeXIweSljRUMzuHFCJdUn0wc6OcjtTDns6knxjPb7N6LmJeftOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-lock": "^1.4.1", + "clean-git-ref": "^2.0.1", + "crc-32": "^1.2.0", + "diff3": "0.0.3", + "ignore": "^5.1.4", + "minimisted": "^2.0.0", + "pako": "^1.0.10", + "pify": "^4.0.1", + "readable-stream": "^4.0.0", + "sha.js": "^2.4.12", + "simple-get": "^4.0.1" + }, + "bin": { + "isogit": "cli.cjs" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/isomorphic-git/node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -10874,9 +10906,9 @@ } }, "node_modules/jsonwebtoken/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", "dev": true, "license": "ISC", "bin": { @@ -10999,77 +11031,144 @@ "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/liftup": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/liftup/-/liftup-3.0.1.tgz", + "integrity": "sha512-yRHaiQDizWSzoXk3APcA71eOI/UuhEkNN9DiW2Tt44mhYzX4joFoCZlxsSOF7RyeLlfqzFLQI1ngFq3ggMPhOw==", + "dev": true, + "dependencies": { + "extend": "^3.0.2", + "findup-sync": "^4.0.0", + "fined": "^1.2.0", + "flagged-respawn": "^1.0.1", + "is-plain-object": "^2.0.4", + "object.map": "^1.0.1", + "rechoir": "^0.7.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/liftup/node_modules/findup-sync": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", + "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", + "dev": true, + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^4.0.2", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/listr2": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.5.tgz", + "integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^5.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/listr2/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/listr2/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/liftup": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/liftup/-/liftup-3.0.1.tgz", - "integrity": "sha512-yRHaiQDizWSzoXk3APcA71eOI/UuhEkNN9DiW2Tt44mhYzX4joFoCZlxsSOF7RyeLlfqzFLQI1ngFq3ggMPhOw==", + "node_modules/listr2/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", "dev": true, - "dependencies": { - "extend": "^3.0.2", - "findup-sync": "^4.0.0", - "fined": "^1.2.0", - "flagged-respawn": "^1.0.1", - "is-plain-object": "^2.0.4", - "object.map": "^1.0.1", - "rechoir": "^0.7.0", - "resolve": "^1.19.0" - }, - "engines": { - "node": ">=10" - } + "license": "MIT" }, - "node_modules/liftup/node_modules/findup-sync": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", - "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", + "node_modules/listr2/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, + "license": "MIT", "dependencies": { - "detect-file": "^1.0.0", - "is-glob": "^4.0.0", - "micromatch": "^4.0.2", - "resolve-dir": "^1.0.1" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">= 8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/listr2": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz", - "integrity": "sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==", + "node_modules/listr2/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", "dev": true, + "license": "MIT", "dependencies": { - "cli-truncate": "^2.1.0", - "colorette": "^2.0.16", - "log-update": "^4.0.0", - "p-map": "^4.0.0", - "rfdc": "^1.3.0", - "rxjs": "^7.5.1", - "through": "^2.3.8", - "wrap-ansi": "^7.0.0" + "ansi-regex": "^6.2.2" }, "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "enquirer": ">= 2.3.0 < 3" + "node": ">=12" }, - "peerDependenciesMeta": { - "enquirer": { - "optional": true - } + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/listr2/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "node_modules/listr2/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", "dev": true, + "license": "MIT", "dependencies": { - "tslib": "^2.1.0" + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/livereload-js": { @@ -11223,85 +11322,219 @@ } }, "node_modules/log-update": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", - "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-escapes": "^4.3.0", - "cli-cursor": "^3.1.0", - "slice-ansi": "^4.0.0", - "wrap-ansi": "^6.2.0" + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/log-update/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/log-update/node_modules/ansi-escapes": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", + "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", "dev": true, + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "environment": "^1.0.0" }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/log-update/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/log-update/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/log-update/node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", "dev": true, + "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "restore-cursor": "^5.0.0" }, "engines": { - "node": ">=7.0.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/log-update/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "node_modules/log-update/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, "node_modules/log-update/node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, + "node_modules/log-update/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/log-update/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/lowercase-keys": { @@ -11857,6 +12090,19 @@ "node": ">=6" } }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/mimic-response": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", @@ -11867,10 +12113,11 @@ } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -11952,18 +12199,6 @@ "node": ">=0.10.0" } }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, "node_modules/moment": { "version": "2.30.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", @@ -11987,17 +12222,16 @@ "dev": true }, "node_modules/nan": { - "version": "2.25.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.25.0.tgz", - "integrity": "sha512-0M90Ag7Xn5KMLLZ7zliPWP3rT90P6PN+IzVFS0VqmnPktBk3700xUVv8Ikm9EUaUE5SDWdp/BIxdENzVznpm1g==", + "version": "2.28.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.28.0.tgz", + "integrity": "sha512-fTsDz99OTq2sVePhGdp4qQhggZFtKr64ZNVyVajRKtMOkJxYekplBh577PiJB12v/D3s2E5cGtOI45LWp6rnLQ==", "dev": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "version": "3.3.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", + "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", "funding": [ { "type": "github", @@ -12084,15 +12318,19 @@ } }, "node_modules/nopt": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "integrity": "sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", "dev": true, + "license": "ISC", "dependencies": { "abbrev": "1" }, "bin": { "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" } }, "node_modules/normalize-path": { @@ -12560,35 +12798,6 @@ "node": ">=8" } }, - "node_modules/os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "deprecated": "This package is no longer supported.", - "dev": true, - "dependencies": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, "node_modules/ospath": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz", @@ -12636,29 +12845,14 @@ }, "node_modules/p-locate": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "dependencies": { - "aggregate-error": "^3.0.0" + "p-limit": "^2.2.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, "node_modules/p-try": { @@ -12692,9 +12886,9 @@ "dev": true }, "node_modules/pako": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", - "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==", + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", "dev": true, "license": "(MIT AND Zlib)" }, @@ -12759,6 +12953,22 @@ "node": ">=8" } }, + "node_modules/path-expression-matcher": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.6.2.tgz", + "integrity": "sha512-enSlaiat05iasnzmgNxRj8reFdj3puY2QpNgP1aPIaVfT6nn9ICuPoFlKHk8EN22HcwewshO+mN2DGbkCEOtqQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -12836,9 +13046,9 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", "dev": true, "license": "MIT" }, @@ -12899,24 +13109,6 @@ "node": ">=8" } }, - "node_modules/pkijs": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/pkijs/-/pkijs-3.3.3.tgz", - "integrity": "sha512-+KD8hJtqQMYoTuL1bbGOqxb4z+nZkTAwVdNtWwe8Tc2xNbEmdJYIYoc6Qt0uF55e6YW6KuTHw1DjQ18gMhzepw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@noble/hashes": "1.4.0", - "asn1js": "^3.0.6", - "bytestreamjs": "^2.0.1", - "pvtsutils": "^1.3.6", - "pvutils": "^1.1.3", - "tslib": "^2.8.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, "node_modules/posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", @@ -12937,9 +13129,9 @@ } }, "node_modules/postcss": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", - "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "version": "8.5.20", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.20.tgz", + "integrity": "sha512-lW616l85ucIQL+FocMmL7pQFPqBmwejrCMg+iPxyImlrANNJG9NHq/RkyCZopDhd8C3LA03PHRJDjkbGu8vvug==", "funding": [ { "type": "opencollective", @@ -12956,7 +13148,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", + "nanoid": "^3.3.16", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -12976,9 +13168,9 @@ } }, "node_modules/prettier": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", - "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", + "version": "3.9.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.5.tgz", + "integrity": "sha512-/FVl766LpUfB5vXgCYOYa0MeV/441Ia99AeICQIQFTY/Nw0roZwULcXpku5i1/m5kt/baz+s4Zogspd839HSMg==", "dev": true, "license": "MIT", "bin": { @@ -13012,12 +13204,6 @@ "node": ">= 0.6.0" } }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, "node_modules/process-on-spawn": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", @@ -13060,13 +13246,6 @@ "integrity": "sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==", "dev": true }, - "node_modules/ps-man": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/ps-man/-/ps-man-1.1.8.tgz", - "integrity": "sha512-ZKDPZwHLYVWIk/Q75N7jCFbuQyokSg2+3WBlt8l35S/uBvxoc+LiRUbb3RUt83pwW82dzwiCpoQIHd9PAxUzHg==", - "dev": true, - "license": "MIT" - }, "node_modules/pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -13086,34 +13265,15 @@ "node": ">=6" } }, - "node_modules/pvtsutils": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz", - "integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==", - "dev": true, - "license": "MIT", - "dependencies": { - "tslib": "^2.8.1" - } - }, - "node_modules/pvutils": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.5.tgz", - "integrity": "sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16.0.0" - } - }, "node_modules/qs": { - "version": "6.14.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", - "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", + "version": "6.15.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", + "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.1.0" + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" }, "engines": { "node": ">=0.6" @@ -13164,18 +13324,45 @@ "dev": true }, "node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", "dev": true, + "license": "MIT", "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/readable-stream/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" } }, "node_modules/readdirp": { @@ -13202,13 +13389,6 @@ "node": ">= 0.10" } }, - "node_modules/reflect-metadata": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", - "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", - "dev": true, - "license": "Apache-2.0" - }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -13524,10 +13704,25 @@ } }, "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" }, "node_modules/safe-json-parse": { "version": "1.0.1", @@ -13551,48 +13746,50 @@ "dev": true }, "node_modules/sass": { - "version": "1.97.3", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.97.3.tgz", - "integrity": "sha512-fDz1zJpd5GycprAbu4Q2PV/RprsRtKC/0z82z0JLgdytmcq0+ujJbJ/09bPGDxCLkKY3Np5cRAOcWiVkLXJURg==", + "version": "1.101.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.101.0.tgz", + "integrity": "sha512-OL3GoQyoUdDt843DpVmDO6y2k1sc5IhUDSpu8XucEI+35neq5QivZ1iuegnpraEVTJXlQGK1gl27zKcTLEPbQw==", "dev": true, "license": "MIT", "dependencies": { - "chokidar": "^4.0.0", - "immutable": "^5.0.2", + "chokidar": "^5.0.0", + "immutable": "^5.1.5", "source-map-js": ">=0.6.2 <2.0.0" }, "bin": { "sass": "sass.js" }, "engines": { - "node": ">=14.0.0" + "node": ">=20.19.0" }, "optionalDependencies": { "@parcel/watcher": "^2.4.1" } }, "node_modules/sass/node_modules/chokidar": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz", - "integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", "dev": true, + "license": "MIT", "dependencies": { - "readdirp": "^4.0.1" + "readdirp": "^5.0.0" }, "engines": { - "node": ">= 14.16.0" + "node": ">= 20.19.0" }, "funding": { "url": "https://paulmillr.com/funding/" } }, "node_modules/sass/node_modules/readdirp": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", - "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">= 14.16.0" + "node": ">= 20.19.0" }, "funding": { "type": "individual", @@ -13600,9 +13797,9 @@ } }, "node_modules/sax": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.4.tgz", - "integrity": "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", + "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -13616,23 +13813,12 @@ "license": "MIT" }, "node_modules/select2": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/select2/-/select2-4.0.13.tgz", - "integrity": "sha512-1JeB87s6oN/TDxQQYCvS5EFoQyvV6eYMZZ0AeA4tdFDYWN3BAGZ8npr17UBFddU0lgAt3H0yjX3X6/ekOj1yjw==", - "license": "MIT" - }, - "node_modules/selfsigned": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-5.5.0.tgz", - "integrity": "sha512-ftnu3TW4+3eBfLRFnDEkzGxSF/10BJBkaLJuBHZX0kiPS7bRdlpZGu6YGt4KngMkdTwJE6MbjavFpqHvqVt+Ew==", - "dev": true, + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/select2/-/select2-4.1.0.tgz", + "integrity": "sha512-i9KalWOP4/LRRGc8+rj2krNm0ZqP14cV+j1TRCEBSsOhCPkKH8rYZ2MCRXcgvqIqN+llqGci0hj9aVkCMvL0+g==", "license": "MIT", - "dependencies": { - "@peculiar/x509": "^1.14.2", - "pkijs": "^3.3.3" - }, "engines": { - "node": ">=18" + "node": ">=24" } }, "node_modules/semver": { @@ -13781,27 +13967,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/sha.js/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -13849,15 +14014,15 @@ } }, "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" }, @@ -13869,14 +14034,14 @@ } }, "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" + "object-inspect": "^1.13.4" }, "engines": { "node": ">= 0.4" @@ -13994,52 +14159,51 @@ } }, "node_modules/slice-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", - "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-8.0.0.tgz", + "integrity": "sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" + "ansi-styles": "^6.2.3", + "is-fullwidth-code-point": "^5.1.0" }, "engines": { - "node": ">=8" + "node": ">=20" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/slice-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", "dev": true, + "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "get-east-asian-width": "^1.3.1" }, "engines": { - "node": ">=7.0.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/slice-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "node_modules/snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -14394,12 +14558,13 @@ } }, "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, + "license": "MIT", "dependencies": { - "safe-buffer": "~5.1.0" + "safe-buffer": "~5.2.0" } }, "node_modules/string-template": { @@ -14507,9 +14672,9 @@ } }, "node_modules/strnum": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.2.tgz", - "integrity": "sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.4.1.tgz", + "integrity": "sha512-M9eUSMT2dCB2cTNPG7UYj6KuK7RJR2SN2+yCV/fTW3xzTCS6EaGZ5pSMgDIjB7r8zSfTGk+dvvn9rTjpVS9Mwg==", "dev": true, "funding": [ { @@ -14517,7 +14682,10 @@ "url": "https://github.com/sponsors/NaturalIntelligence" } ], - "license": "MIT" + "license": "MIT", + "dependencies": { + "anynum": "^1.0.1" + } }, "node_modules/superjson": { "version": "2.2.2", @@ -14556,9 +14724,9 @@ } }, "node_modules/systeminformation": { - "version": "5.31.5", - "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.31.5.tgz", - "integrity": "sha512-5SyLdip4/3alxD4Kh+63bUQTJmu7YMfYQTC+koZy7X73HgNqZSD2P4wOZQWtUncvPvcEmnfIjCoygN4MRoEejQ==", + "version": "5.31.17", + "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.31.17.tgz", + "integrity": "sha512-TvFA9iwDWlMjqZVlKIJ0Cy+Zgm9ttlMx0SMRwJDMNKyhlEKWBMb3+WRwDi/3dvHdWbexpos4Osp4U49p5WjB5g==", "dev": true, "license": "MIT", "os": [ @@ -16667,12 +16835,6 @@ "integrity": "sha512-rkTVqu6IjfQ/6+uNuuc3sZek4CEYxTJom3IktzgdSxcZqdARuebbA/f4QmAxMQIxqq9ZLEUkSYqvuk1I6VKq4g==", "dev": true }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true - }, "node_modules/tiny-emitter": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", @@ -16763,27 +16925,6 @@ "dev": true, "license": "MIT" }, - "node_modules/to-buffer/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", @@ -16886,33 +17027,6 @@ "node": ">= 8" } }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, - "license": "0BSD" - }, - "node_modules/tsyringe": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/tsyringe/-/tsyringe-4.10.0.tgz", - "integrity": "sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tslib": "^1.9.3" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/tsyringe/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true, - "license": "0BSD" - }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -16974,12 +17088,6 @@ "node": ">= 0.4" } }, - "node_modules/typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", - "dev": true - }, "node_modules/typedarray-to-buffer": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", @@ -17297,16 +17405,6 @@ "browserslist": ">= 4.21.0" } }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, "node_modules/uri-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/uri-path/-/uri-path-1.0.0.tgz", @@ -17586,16 +17684,16 @@ } }, "node_modules/vue": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.30.tgz", - "integrity": "sha512-hTHLc6VNZyzzEH/l7PFGjpcTvUgiaPK5mdLkbjrTeWSRcEfxFrv56g/XckIYlE9ckuobsdwqd5mk2g1sBkMewg==", + "version": "3.5.40", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.40.tgz", + "integrity": "sha512-+8PJ4SJXdn/cHGImF4CKdxlWHIN5Dkt7DoufRREM6h6uVCx2m7QxgcEQmmzyOK8A9mcafg7sFbJFYsdFVubTig==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.30", - "@vue/compiler-sfc": "3.5.30", - "@vue/runtime-dom": "3.5.30", - "@vue/server-renderer": "3.5.30", - "@vue/shared": "3.5.30" + "@vue/compiler-dom": "3.5.40", + "@vue/compiler-sfc": "3.5.40", + "@vue/runtime-dom": "3.5.40", + "@vue/server-renderer": "3.5.40", + "@vue/shared": "3.5.40" }, "peerDependencies": { "typescript": "*" @@ -17623,10 +17721,11 @@ } }, "node_modules/websocket-driver": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.5.tgz", + "integrity": "sha512-ZL2+3c7kMBdIRCMz6l8jQMHyGVxj+UL+xVk74Ombiciboca8rHa15L86B19E5oh1pL9Ii/uj54gtsIrZGMo6zA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", @@ -17667,14 +17766,14 @@ "dev": true }, "node_modules/which-typed-array": { - "version": "1.1.20", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", - "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", + "version": "1.1.22", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.22.tgz", + "integrity": "sha512-fvO4ExWMFsqyhG3AiPAObMuY1lxaqgYcxbc49CNdWDDECOJNgQyvsOWVwbZc+qf3rzRtxojBK+CMEv0Ld5CYpw==", "dev": true, "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", + "call-bind": "^1.0.9", "call-bound": "^1.0.4", "for-each": "^0.3.5", "get-proto": "^1.0.1", @@ -17808,9 +17907,9 @@ } }, "node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", "dev": true, "license": "MIT", "engines": { @@ -17829,6 +17928,22 @@ } } }, + "node_modules/xml-naming": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.3.0.tgz", + "integrity": "sha512-ghig2TBE/H11aOVgmahA3MhimvkBr6JIYknH/Dhdk10nXwdbIqBJsbfMxpvFPG8bAw77gN29aQWvKpmVoPlvPQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/xml2js": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", @@ -17904,16 +18019,6 @@ "node": ">=12" } }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "dev": true, - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, "node_modules/yoctocolors-cjs": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz", @@ -17926,6 +18031,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/zstddec": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/zstddec/-/zstddec-0.2.0.tgz", + "integrity": "sha512-oyPnDa1X5c13+Y7mA/FDMNJrn4S8UNBe0KCqtDmor40Re7ALrPN6npFwyYVRRh+PqozZQdeg23QtbcamZnG5rA==", + "dev": true, + "license": "MIT AND BSD-3-Clause" + }, "node_modules/zwitch": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", diff --git a/package.json b/package.json index 64700cc75..704a24cca 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "commonsbooking", - "version": "2.10.10", + "version": "2.11", "description": "Wordpress plugin for managing and booking of common goods.", "author": "The CommonsBooking Team ", "license": "SEE LICENSE IN LICENSE.txt", @@ -9,12 +9,12 @@ "url": "https://github.com/wielebenwir/cb" }, "devDependencies": { - "@babel/preset-env": "^7.29.2", - "@wordpress/env": "^11.0.0", + "@babel/preset-env": "^7.29.7", + "@wordpress/env": "^11.11.0", "commons-api": "git+https://github.com/wielebenwir/commons-api.git", - "cypress": "^15.13.1", + "cypress": "^15.18.1", "editorconfig": "^3.0.2", - "grunt": "^1.6.1", + "grunt": "^1.6.2", "grunt-babel": "^8.0.0", "grunt-cli": "^1.5.0", "grunt-contrib-clean": "^2.0.1", @@ -27,15 +27,17 @@ "grunt-dart-sass": "^2.0.1", "matchdep": "^2.0.0", "medium-zoom": "^1.1.0", - "sass": "^1.97.3", + "sass": "^1.101.0", "vitepress": "^1.6.4", - "prettier": "^3.3.3" + "prettier": "^3.9.5" }, "scripts": { "start": "composer install --ignore-platform-reqs && npm install && npm run dist", "env": "wp-env", "env:start": "wp-env start", "env:stop": "wp-env stop", + "env:test:start": "wp-env start --config=.wp-env.test.json", + "env:test:stop": "wp-env stop --config=.wp-env.test.json", "cypress:setup": "./bin/setup-cypress-env.sh", "cypress:open": "cypress open --config-file tests/cypress/cypress.config.js", "cypress:run": "cypress run --config-file tests/cypress/cypress.config.js", @@ -53,9 +55,9 @@ "leaflet.markercluster": "^1.5.0", "moment": "^2.19.4", "search-insights": "^2.17.3", - "select2": "^4.0.13", + "select2": "^4.1.0", "shufflejs": "^6.1.1", "spin.js": "^2.3.2", - "vue": "^3.5.30" + "vue": "^3.5.40" } } diff --git a/readme.txt b/readme.txt index fcbcb10a3..cc1911709 100644 --- a/readme.txt +++ b/readme.txt @@ -3,8 +3,8 @@ Contributors: wielebenwirteam, m0rb, flegfleg, chriwen, hansmorb, datengraben Donate link: https://www.wielebenwir.de/verein/unterstutzen Tags: booking, calendar, sharing, commoning, open-source Requires at least: 5.9 -Tested up to: 6.9 -Stable Tag: 2.10.10 +Tested up to: 7.0 +Stable Tag: 2.11 Requires PHP: 8.1 License: GPLv2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html @@ -81,6 +81,27 @@ CommonsBooking was developed for the ["Commons Cargobike" movement](http://commo ## Changelog +FIXED: Admin list for items and locations are able to filter by their respective category + +### 2.11 (13.07.2026) +ADDED: GBFS routes vehicle_availability.json, vehicle_types.json, vehicle_status.json +ADDED: Multi-select now also available for timeframes of type repair +ADDED: Checkbox to exclude individual items from API shares +ADDED: Filter hook for external plugins to add additional GBFS feeds +ENHANCED: GBFS updated to version 3.1-RC3 +ENHANCED: iCalendar feed now differentiates between a users own bookings and other users bookings, using two different types of templates +ENHANCED: Better performance through pre-fetching timeframes for each item +ENHANCED: API Keys can now also be passed using HTTP headers (using apikey as key and the key as the value) +ENHANCED: GBFS system_id now uses human-readable format +FIXED: Admins could not cancel bookings of other users through frontend (thx @nelarsen) +FIXED: Fixed filter hook commonsbooking_isCurrentUserAdmin and changed to to commonsbooking_isUserAdmin (see documentation) +FIXED: Updated CMB2 to fix checkboxes breaking with WP 7.0 +FIXED: Users could delete already confirmed bookings (thx @poilu) +FIXED: GBFS availability of bikes had a timezone issue +FIXED: GBFS station_information syntax was incorrect +FIXED: Booking rule "Maximum of bookable days in time period" would not work for uneven amount of days +FIXED: Better compatibility with other plugins by dependency prefixing using Strauss (thx to @BrianHenryIE) + ### 2.10.10 (23.03.2026) FIXED: Two users booking same item possible when two users tried to book the same time period (thx @nelarsen) FIXED: Location specific sending of booking start / end reminder (for location owners) always sent email, not only when it is checked at location (thx @poilu) diff --git a/src/API/AvailabilityRoute.php b/src/API/AvailabilityRoute.php index 026256be6..5eeecfe3e 100644 --- a/src/API/AvailabilityRoute.php +++ b/src/API/AvailabilityRoute.php @@ -38,12 +38,12 @@ class AvailabilityRoute extends BaseRoute { /** * This retrieves bookable timeframes and the different items assigned, with their respective availability. * - * @param bool $id The id of a {@see \CommonsBooking\Wordpress\CustomPostType\Item::post_type} post to search for + * @param ?int $id The id of a {@see \CommonsBooking\Wordpress\CustomPostType\Item::post_type} post to search for * * @return array * @throws Exception */ - public function getItemData( $id = false ): array { + public static function getItemData( $id = null ): array { $calendar = new Calendar( new Day( date( 'Y-m-d', time() ) ), new Day( date( 'Y-m-d', strtotime( '+2 weeks' ) ) ), // TODO why two weeks? seems like a configurable option diff --git a/src/API/BaseRoute.php b/src/API/BaseRoute.php index 5e13be79d..a9824fab3 100644 --- a/src/API/BaseRoute.php +++ b/src/API/BaseRoute.php @@ -6,8 +6,8 @@ use Exception; use RuntimeException; +use CommonsBooking\Helper\Feature; use CommonsBooking\Repository\ApiShares; -use CommonsBooking\Settings\Settings; use CommonsBooking\Opis\JsonSchema\Validator; use CommonsBooking\Opis\JsonSchema\Errors\ErrorFormatter; use WP_REST_Controller; @@ -178,16 +178,40 @@ public function escapeJsonString( $string ) { return substr( wp_json_encode( $string ), 1, - 1 ) ? : ''; } + /** + * Decodes HTML entities in a post title for API output. + * + * WordPress stores post titles with encoded entities (e.g. "A&B"). + * Since the API returns plain text values that consumers render as text, + * we decode them so they receive "A&B" instead of "A&B". + * + * @param string $title + * + * @return string + */ + protected function decodeApiTitle( string $title ): string { + return html_entity_decode( $title, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5, 'UTF-8' ); + } + /** * Returns true if current request is allowed. * * @return bool */ public static function hasPermission(): bool { - $isApiActive = Settings::getOption( 'commonsbooking_options_api', 'api-activated' ); - $anonymousAccessAllowed = Settings::getOption( 'commonsbooking_options_api', 'apikey_not_required' ); + $isApiActive = Feature::isApiEnabled(); + $anonymousAccessAllowed = Feature::isApiAnonymousAccessAllowed(); $apiKey = array_key_exists( self::API_KEY_PARAM, $_REQUEST ) ? sanitize_text_field( $_REQUEST[ self::API_KEY_PARAM ] ) : false; - $apiShare = ApiShares::getByKey( $apiKey ); + if ( ! $apiKey ) { + // get apikey from headers (#2251) + if ( function_exists( 'getallheaders' ) ) { + $allHeaders = array_change_key_case( getallheaders(), CASE_LOWER ); + $apiKey = array_key_exists( self::API_KEY_PARAM, $allHeaders ) ? sanitize_text_field( $allHeaders[ self::API_KEY_PARAM ] ) : false; + } else { + $apiKey = array_key_exists( 'HTTP_' . strtoupper( self::API_KEY_PARAM ), $_SERVER ) ? sanitize_text_field( $_SERVER[ 'HTTP_' . strtoupper( self::API_KEY_PARAM ) ] ) : false; + } + } + $apiShare = ApiShares::getByKey( $apiKey ); // Only if api is active we return something if ( $isApiActive ) { diff --git a/src/API/GBFS/BaseRoute.php b/src/API/GBFS/BaseRoute.php index f44c3ecfc..cc17cc5ba 100644 --- a/src/API/GBFS/BaseRoute.php +++ b/src/API/GBFS/BaseRoute.php @@ -4,6 +4,8 @@ namespace CommonsBooking\API\GBFS; use CommonsBooking\Repository\Location; +use CommonsBooking\Repository\PostRepository; +use CommonsBooking\Wordpress\CustomPostType\MetaField; use Exception; use stdClass; use WP_REST_Request; @@ -11,10 +13,15 @@ /** * Base class which implements retrieval of basic data attributes of - * GBFS spec. + * GBFS spec. Derive from this class, when you want to have a route that iterates over CustomPosts. * - * Note: When deriving from this class, implement \WP_REST_Controller::prepare_item_for_response, - * which is called in \BaseRoute::getItemData + * Note: When deriving from this class + * - implement \WP_REST_Controller::prepare_item_for_response, + * which is called in \BaseRoute::getItemData + * - implement $rest_base + * - implement $schemaUrl + * - (if necessary) overwrite getRepository + * - (if necessary) overwrite getListName */ class BaseRoute extends \CommonsBooking\API\BaseRoute { @@ -26,18 +33,14 @@ class BaseRoute extends \CommonsBooking\API\BaseRoute { * @return WP_REST_Response */ public function get_items( $request ): WP_REST_Response { - $response = new stdClass(); - $response->data = new stdClass(); - $response->data->stations = $this->getItemData( $request ); - $response->last_updated = date( 'c' ); // ISO-8601 timestamp - $response->ttl = 60; - $response->version = '3.1-RC2'; + $response = new stdClass(); + $response->data = new stdClass(); + $response->data->{static::getListName()} = $this->getItemData( $request ); + $response->last_updated = date( 'c' ); // ISO-8601 timestamp + $response->ttl = 60; + $response->version = '3.1-RC3'; - if ( WP_DEBUG ) { - $this->validateData( $response ); - } - - return new WP_REST_Response( $response, 200 ); + return $this->respond_with_validation( $response ); } /** @@ -48,12 +51,15 @@ public function get_items( $request ): WP_REST_Response { * @return array */ public function getItemData( $request ): array { - $data = []; - $locations = Location::get(); + $data = []; + $items = static::getRepository()::get(); - foreach ( $locations as $location ) { + foreach ( $items as $item ) { + if ( $item->getMeta( MetaField::ItemApiExclude->getFieldId() ) == 'on' ) { + continue; + } try { - $itemdata = $this->prepare_item_for_response( $location, $request ); + $itemdata = $this->prepare_item_for_response( $item, $request ); $data[] = $itemdata->data; } catch ( Exception $exception ) { if ( WP_DEBUG ) { @@ -64,4 +70,23 @@ public function getItemData( $request ): array { return $data; } + + /** + * Overwrite this, if you don't iterate over stations but need the resulting items in a list with a different name + * + * @return string + */ + protected static function getListName(): string { + return 'stations'; + } + + /** + * The post type that the route will iterate over. + * By default, these are all the locations. + * + * @return PostRepository + */ + protected static function getRepository(): PostRepository { + return new Location(); + } } diff --git a/src/API/GBFS/Discovery.php b/src/API/GBFS/Discovery.php index 0a31b16e9..0f923c88f 100644 --- a/src/API/GBFS/Discovery.php +++ b/src/API/GBFS/Discovery.php @@ -34,23 +34,36 @@ class Discovery extends \CommonsBooking\API\BaseRoute { */ public function get_items( $request ): WP_REST_Response { - $feeds = array(); - $feeds[] = $this->get_feed( 'system_information' ); - $feeds[] = $this->get_feed( 'station_information' ); - $feeds[] = $this->get_feed( 'station_status' ); + /** + * The names of the feeds that are available in the GBFS route. + * They will be announced through the gbfs.json. + * The routes still need to be registered using register_rest_route. + * + * @since 2.11 + * + * @param String[] $raw_feeds the names of the feeds without a .json suffix + */ + $raw_feeds = apply_filters( + 'commonsbooking_gbfs_feeds', + [ + 'system_information', + 'station_information', + 'station_status', + 'vehicle_availability', + 'vehicle_status', + 'vehicle_types', + ] + ); + $feeds = array_map( fn( $feed ) => $this->get_feed( $feed ), $raw_feeds ); $response = new stdClass(); $response->data = new stdClass(); $response->data->feeds = $feeds; $response->last_updated = date( 'c' ); // ISO-8601 timestamp $response->ttl = 86400; - $response->version = '3.1-RC2'; + $response->version = '3.1-RC3'; - if ( WP_DEBUG ) { - $this->validateData( $response ); - } - - return new WP_REST_Response( $response, 200 ); + return $this->respond_with_validation( $response ); } private function get_feed( $name ): stdClass { diff --git a/src/API/GBFS/StationInformation.php b/src/API/GBFS/StationInformation.php index 807cffaee..a0ad9e46a 100644 --- a/src/API/GBFS/StationInformation.php +++ b/src/API/GBFS/StationInformation.php @@ -35,10 +35,10 @@ class StationInformation extends BaseRoute { */ public function prepare_item_for_response( $item, $request ): WP_REST_Response { $preparedItem = new stdClass(); - $preparedItem->station_id = $item->ID . ''; + $preparedItem->station_id = strval( $item->ID ); $preparedItem->name = [ (object) [ - 'text' => $item->post_title, + 'text' => $this->decodeApiTitle( $item->post_title ), 'language' => get_bloginfo( 'language' ), ], ]; diff --git a/src/API/GBFS/StationStatus.php b/src/API/GBFS/StationStatus.php index 85221c454..b8badd899 100644 --- a/src/API/GBFS/StationStatus.php +++ b/src/API/GBFS/StationStatus.php @@ -3,11 +3,9 @@ namespace CommonsBooking\API\GBFS; -use CommonsBooking\Helper\Wordpress; -use CommonsBooking\Model\Calendar; -use CommonsBooking\Model\Day; use CommonsBooking\Model\Location; use CommonsBooking\Repository\Item; +use CommonsBooking\Wordpress\CustomPostType\MetaField; use stdClass; use WP_REST_Response; @@ -28,61 +26,34 @@ class StationStatus extends BaseRoute { protected $schemaUrl = COMMONSBOOKING_PLUGIN_DIR . 'includes/gbfs-json-schema/station_status.json'; /** - * @param Location $item + * @param Location $location * @param $request * * @return WP_REST_Response * @throws \Exception */ - public function prepare_item_for_response( $item, $request ): WP_REST_Response { - $preparedItem = new stdClass(); - $preparedItem->station_id = $item->ID . ''; - $preparedItem->num_vehicles_available = $this->getItemCountAtLocation( $item->ID ); - $preparedItem->is_installed = true; - $preparedItem->is_renting = true; - $preparedItem->is_returning = true; - $preparedItem->last_reported = date( 'c' ); // ISO-8601 timestamp + public function prepare_item_for_response( $location, $request ): WP_REST_Response { + $availableItems = count( + array_filter( + Item::getByLocation( $location->ID, true ), + fn( $item ) => $item->isCurrentlyFreeAtLocation( $location->ID, true ) && $item->getMeta( MetaField::ItemApiExclude->getFieldId() ) != 'on' + ) + ); + + $preparedItem = new stdClass(); + $preparedItem->station_id = strval( $location->ID ); + $preparedItem->num_vehicles_available = $availableItems; + $preparedItem->vehicle_types_available = [ + (object) [ + 'vehicle_type_id' => VehicleTypes::DEFAULT_NAME, + 'count' => $availableItems, + ], + ]; + $preparedItem->is_installed = true; + $preparedItem->is_renting = true; + $preparedItem->is_returning = true; + $preparedItem->last_reported = date( 'c' ); // ISO-8601 timestamp return new WP_REST_Response( $preparedItem ); } - - /** - * Will get the amount of items that are currently in the location - * and marked as "green" (bookable right now by the user) for the current time. - * This purposefully excludes items that have a Holiday Timeframe, are bookable in advance - * or can only be booked through overbooking. - * This is because the GBFS spec only accounts for items available in that instant. - * - * @param int $locationId - * - * @return int - * @throws \Exception - */ - private function getItemCountAtLocation( $locationId ): int { - $items = Item::getByLocation( $locationId, true ); - $nowDT = Wordpress::getUTCDateTimeByTimestamp( current_time( 'timestamp' ) ); - $availableCounter = 0; - foreach ( $items as $item ) { - // we have to make our calendar span at least one day, otherwise we get no results - $itemCalendar = new Calendar( - new Day( date( 'Y-m-d', strtotime( '-1 day' ) ) ), - new Day( date( 'Y-m-d', strtotime( '+1 day' ) ) ), - [ $locationId ], - [ $item->ID ] - ); - $availabilitySlots = $itemCalendar->getAvailabilitySlots(); - // we have to iterate over multiple slots because the calendar will give us more than we asked for - foreach ( $availabilitySlots as $availabilitySlot ) { - // match our exact current time to the slot - $startDT = new \DateTime( $availabilitySlot->start ); - $endDT = new \DateTime( $availabilitySlot->end ); - if ( $nowDT >= $startDT && $nowDT <= $endDT ) { - ++$availableCounter; - // break out of the loop, we only need one match of availability per item - break; - } - } - } - return $availableCounter; - } } diff --git a/src/API/GBFS/SystemInformation.php b/src/API/GBFS/SystemInformation.php index 7eb4e4ad1..95fd9c512 100644 --- a/src/API/GBFS/SystemInformation.php +++ b/src/API/GBFS/SystemInformation.php @@ -3,6 +3,8 @@ namespace CommonsBooking\API\GBFS; +use CommonsBooking\CB\CB; +use CommonsBooking\Repository\Timeframe; use stdClass; use WP_REST_Response; @@ -36,19 +38,24 @@ public function get_items( $request ): WP_REST_Response { 'language' => get_bloginfo( 'language' ), ], ]; - $response->data->opening_hours = '24/7'; // TODO: Close, when no items are available - $response->data->system_id = sha1( site_url() ); + $response->data->opening_hours = $this->isOpen() ? '24/7' : '24/7 closed'; + $response->data->system_id = COMMONSBOOKING_PLUGIN_SLUG . '_' . strtolower( preg_replace( '/\s+/', '_', get_bloginfo( 'name' ) ) ); $response->data->feed_contact_email = get_bloginfo( 'admin_email' ); $response->data->languages = [ get_bloginfo( 'language' ) ]; $response->data->timezone = $tz; $response->last_updated = date( 'c' ); // ISO-8601 timestamp; $response->ttl = 86400; - $response->version = '3.1-RC2'; + $response->version = '3.1-RC3'; - if ( WP_DEBUG ) { - $this->validateData( $response ); - } + return $this->respond_with_validation( $response ); + } - return new WP_REST_Response( $response, 200 ); + private function isOpen(): bool { + $timeframes = Timeframe::getBookable( + [], + [], + date( CB::getInternalDateFormat(), current_time( 'timestamp' ) ), + ); + return count( $timeframes ) > 0; } } diff --git a/src/API/GBFS/VehicleAvailability.php b/src/API/GBFS/VehicleAvailability.php new file mode 100644 index 000000000..f02b522f3 --- /dev/null +++ b/src/API/GBFS/VehicleAvailability.php @@ -0,0 +1,89 @@ +getLocation(); + if ( ! $location ) { + throw new \Exception( 'No location for item. (ID: ' . $item->ID . ')' ); + } + + $preparedItem = new stdClass(); + $preparedItem->vehicle_id = strval( $item->getCloakedId() ); + $preparedItem->vehicle_type_id = VehicleTypes::DEFAULT_NAME; + $preparedItem->station_id = strval( $location->ID ); // This is what you could consider the home location. Regardless if the item is there atm or not. + $preparedItem->availabilities = self::getAvailabilities( $item ); + + return new WP_REST_Response( $preparedItem ); + } + + private static function getAvailabilities( $item ): array { + $availabilities = AvailabilityRoute::getItemData( $item->ID ); + + if ( empty( $availabilities ) ) { + return []; + } + + $firstAvailability = array_shift( $availabilities ); + $slots = [ + (object) [ + 'from' => $firstAvailability->start, + 'until' => $firstAvailability->end, + ], + ]; + + foreach ( $availabilities as $availability ) { + $gapSeconds = strtotime( $availability->start ) - strtotime( end( $slots )->until ); + + if ( $gapSeconds < 59 ) { + end( $slots )->until = $availability->end; + } else { + $slots[] = (object) [ + 'from' => $availability->start, + 'until' => $availability->end, + ]; + } + } + + return $slots; + } + + protected static function getListName(): string { + return 'vehicles'; + } + + + protected static function getRepository(): PostRepository { + // we iterate over posts with cb_item post type + return new Item(); + } +} diff --git a/src/API/GBFS/VehicleStatus.php b/src/API/GBFS/VehicleStatus.php new file mode 100644 index 000000000..180357a75 --- /dev/null +++ b/src/API/GBFS/VehicleStatus.php @@ -0,0 +1,134 @@ +getLocation(); + + if ( ! $location ) { + throw new \Exception( 'No location for item. (ID: ' . $item->ID . ')' ); + } + + // Vehicles that are part of an active rental MUST NOT appear in this feed + if ( ! $item->isCurrentlyFreeAtLocation( $location->ID, true, true ) ) { + throw new \Exception( 'Item currently not available (skipped in VehicleStatus) ' . '(ID: ' . $item->ID . ')' ); + } + + $preparedItem = new stdClass(); + $preparedItem->vehicle_id = strval( $item->getCloakedId() ); + $preparedItem->vehicle_type_id = VehicleTypes::DEFAULT_NAME; + $preparedItem->station_id = strval( $location->ID ); + $preparedItem->is_reserved = false; // this never happens, we do not know the difference between the start of a booking period and if it has actually been picked up + $preparedItem->is_disabled = $this->isDisabled( $item, $location ); + $preparedItem->rental_uris = (object) [ + 'web' => $item->getCloakedURL(), + ]; + $preparedItem->available_until = $this->getAvailableUntil( $item ); + + return new WP_REST_Response( $preparedItem ); + } + + private function isDisabled( \CommonsBooking\Model\Item $item, Location $location ): bool { + $today = new Day( date( 'Y-m-d', time() ), [ $location->ID ], [ $item->ID ], [ Timeframe::BOOKABLE_ID ] ); + $restrictions = $today->getRestrictions(); + $restrictions = array_filter( + $restrictions, + fn( $restriction ) => $restriction->isActive() && $restriction->getType() == Restriction::TYPE_REPAIR + ); + + if ( empty( $restrictions ) ) { + return false; + } else { + return true; + } + } + + /** + * The date and time when any rental of the vehicle must be completed. + * The vehicle must be returned and made available for the next user by this time. + * If this field is empty, it indicates that the vehicle is available indefinitely. + * This field SHOULD be published by carsharing or other mobility systems where vehicles can be booked in advance for future travel. + * + * @param \CommonsBooking\Model\Item $item + * @return string in ISO 8601 notation + */ + private function getAvailableUntil( \CommonsBooking\Model\Item $item ): string { + $timeframe = $item->getClosestBookableTimeframe(); + + // Counting from the first bookable day (inclusive), maxDays of 3 means + // the item is bookable today, tomorrow, and the day after. Using + // maxDays as-is for the offset would incorrectly point to the fourth, + // unavailable day, so we subtract 1. + $maxDaysOffset = $timeframe->getMaxDays() - 1; + $firstBookableDay = $timeframe->getFirstBookableDay(); + $latestAllowedEnd = new \DateTime( $firstBookableDay . ' +' . $maxDaysOffset . ' day 23:59:59' ); + + $itemCalendar = new Calendar( + new Day( date( 'Y-m-d', strtotime( '-1 day' ) ) ), + new Day( date( 'Y-m-d', strtotime( '+' . $maxDaysOffset . ' day', strtotime( $firstBookableDay ) ) ) ), + [ $timeframe->getLocation()->ID ], + [ $item->ID ] + ); + $itemCalendar->setIgnoreStartDayOffset( true ); + + $slotsInRange = array_filter( + $itemCalendar->getAvailabilitySlots(), + fn( $slot ) => new \DateTime( $slot->end ) <= $latestAllowedEnd + ); + + usort( + $slotsInRange, + fn( $a, $b ) => new \DateTime( $a->end ) <=> new \DateTime( $b->end ) + ); + + $lastSlot = array_pop( $slotsInRange ); + + return ( new \DateTime( $lastSlot->end ) )->format( 'c' ); + } + + protected static function getListName(): string { + return 'vehicles'; + } + + + protected static function getRepository(): PostRepository { + // we iterate over posts with cb_item post type + return new Item(); + } +} diff --git a/src/API/GBFS/VehicleTypes.php b/src/API/GBFS/VehicleTypes.php new file mode 100644 index 000000000..5533d5650 --- /dev/null +++ b/src/API/GBFS/VehicleTypes.php @@ -0,0 +1,52 @@ +data = new stdClass(); + $response->data->vehicle_types = [ + (object) [ + 'vehicle_type_id' => self::DEFAULT_NAME, + 'form_factor' => 'cargo_bicycle', + 'propulsion_type' => 'human', + ], + ]; + $response->last_updated = date( 'c' ); // ISO-8601 timestamp + $response->ttl = 86400; + $response->version = '3.1-RC3'; + + return $this->respond_with_validation( $response ); + } +} diff --git a/src/API/ItemsRoute.php b/src/API/ItemsRoute.php index d8aa3b8c0..83bac2f39 100644 --- a/src/API/ItemsRoute.php +++ b/src/API/ItemsRoute.php @@ -4,6 +4,7 @@ namespace CommonsBooking\API; use CommonsBooking\Repository\Item; +use CommonsBooking\Wordpress\CustomPostType\MetaField; use stdClass; use WP_Error; use WP_REST_Request; @@ -51,7 +52,10 @@ public function getItemData( $request ): stdClass { $items = Item::get( $args ); foreach ( $items as $item ) { - $itemdata = $this->prepare_item_for_response( $item, $request ); + $itemdata = $this->prepare_item_for_response( $item, $request ); + if ( $item->getMeta( MetaField::ItemApiExclude->getFieldId() ) == 'on' ) { + continue; + } $data->items[] = $itemdata->get_data(); } @@ -123,7 +127,7 @@ public function get_item( $request ): WP_REST_Response { public function prepare_item_for_response( $item, $request ): WP_REST_Response { $preparedItem = new stdClass(); $preparedItem->id = $item->ID . ''; - $preparedItem->name = $item->post_title; + $preparedItem->name = $this->decodeApiTitle( $item->post_title ); $preparedItem->url = get_permalink( $item->ID ); $preparedItem->description = $this->escapeJsonString( $item->post_content ); $preparedItem->ownerId = ''; // not implemented, but currently required by schema diff --git a/src/API/LocationsRoute.php b/src/API/LocationsRoute.php index c429278f0..688472706 100644 --- a/src/API/LocationsRoute.php +++ b/src/API/LocationsRoute.php @@ -103,7 +103,7 @@ public function prepare_item_for_response( $item, $request ): WP_REST_Response { $preparedItem->properties = new stdClass(); $preparedItem->properties->id = $item->ID . ''; - $preparedItem->properties->name = $item->post_title; + $preparedItem->properties->name = $this->decodeApiTitle( $item->post_title ); $preparedItem->properties->description = $this->escapeJsonString( $item->post_content ); $preparedItem->properties->url = get_permalink( $item->ID ); $preparedItem->properties->address = $item->formattedAddressOneLine(); diff --git a/src/CB/CB1UserFields.php b/src/CB/CB1UserFields.php index ab13df649..995488cbc 100644 --- a/src/CB/CB1UserFields.php +++ b/src/CB/CB1UserFields.php @@ -8,6 +8,9 @@ use CommonsBooking\Settings\Settings; +/** + * @deprecated since 2.11, to be removed in 2.12 + */ class CB1UserFields { /** @@ -33,7 +36,7 @@ class CB1UserFields { /** * @var array|mixed */ - private $user_vars; // @phpstan-ignore property.onlyWritten + private $user_vars; public function __construct() { @@ -226,7 +229,7 @@ public function registration_add_meta( $user_id ) { /** * Sets a flat array of user field/value pairs * - * @since 2.10 deprecated (cb_object_to_array is unspecified) + * @since 2.10 deprecated (cb_object_to_array is unspecified), removal in 2.12 * @since 0.6 */ public function set_basic_user_vars( $user_id ) { @@ -248,6 +251,7 @@ public function set_basic_user_vars( $user_id ) { /** * Add addiotinal key/value pairs to the user_vars array * + * @deprecated since 2.11, removal in 2.12 * @since 0.5.3 */ public function add_user_vars( $key, $value ) { diff --git a/src/Helper/Feature.php b/src/Helper/Feature.php new file mode 100644 index 000000000..7e4947920 --- /dev/null +++ b/src/Helper/Feature.php @@ -0,0 +1,65 @@ +setTimestamp( diff --git a/src/Map/MapFilter.php b/src/Map/MapFilter.php index 7c3f5e5a4..cb2a839e2 100644 --- a/src/Map/MapFilter.php +++ b/src/Map/MapFilter.php @@ -2,8 +2,20 @@ namespace CommonsBooking\Map; +/** + * Class MapFilter + * + * @deprecated since 2.11, to be removed in 2.12 + */ class MapFilter { + /** + * @deprecated since 2.11, to be removed in 2.12 + * + * @param $item_terms + * @param $category_groups + * @return bool + */ protected static function check_item_terms_against_categories( $item_terms, $category_groups ): bool { $valid_groups_count = 0; diff --git a/src/Migration/Migration.php b/src/Migration/Migration.php index fef012036..613d9e27d 100644 --- a/src/Migration/Migration.php +++ b/src/Migration/Migration.php @@ -16,6 +16,9 @@ use WP_Query; /** + * + * @deprecated since 2.11, will be removed in 2.12 + * * The logic for handling the migration from CB1 to CB2. * The CB1 fields are fetched from the @see \CommonsBooking\Repository\CB1 repository and migrated using the * respective migration functions in this class. diff --git a/src/Model/Calendar.php b/src/Model/Calendar.php index 806b52feb..ed33cf093 100644 --- a/src/Model/Calendar.php +++ b/src/Model/Calendar.php @@ -45,6 +45,27 @@ class Calendar { */ protected array $timeframes; + /** + * When this is enabled, @see Timeframe::META_BOOKING_START_DAY_OFFSET is ignored. + * This is used for the API routes, where we want to show the actual availability of the items, regardless of the booking start day offset. + * + * @var bool + */ + protected bool $ignoreStartDayOffset = false; + + /** + * When this is enabled, restrictions are ignored when creating availabilities. + * This is useful when you want to differentiate between an item that is booked / not available + * and an item that would be bookable but is in repair. + * + * Just passed to the \CommonsBooking\Model\Day model, because restriction calculations are made there + * + * Used in @see \CommonsBooking\API\GBFS\VehicleStatus to differentiate between booked items and disabled items + * + * @var bool + */ + protected bool $ignoreRestrictions = false; + /** * Calendar constructor. * @@ -60,6 +81,9 @@ public function __construct( Day $startDate, Day $endDate, array $locations = [] throw new \InvalidArgumentException( 'Calendar must span at least two days' ); } + $startDate->setIgnoreRestrictions( $this->ignoreRestrictions ); + $endDate->setIgnoreRestrictions( $this->ignoreRestrictions ); + $this->startDate = $startDate; $this->endDate = $endDate; $this->items = $items; @@ -139,6 +163,7 @@ public function getAvailabilitySlots(): array { foreach ( $this->getWeeks() as $week ) { /** @var Day $day */ foreach ( $week->getDays() as $day ) { + $day->setIgnoreRestrictions( $this->ignoreRestrictions ); foreach ( $day->getGrid() as $slot ) { $timeframe = new Timeframe( $slot['timeframe'] ); $timeFrameType = get_post_meta( $slot['timeframe']->ID, 'type', true ); @@ -149,7 +174,7 @@ public function getAvailabilitySlots(): array { } // Skip timeframes that are not bookable today - if ( $timeframe->getFirstBookableDay() > $day->getDate() ) { + if ( ! $this->ignoreStartDayOffset && $timeframe->getFirstBookableDay() > $day->getDate() ) { continue; } @@ -185,4 +210,12 @@ public function getAvailabilitySlots(): array { } return $slots; } + + public function setIgnoreStartDayOffset( bool $ignoreStartDayOffset ): void { + $this->ignoreStartDayOffset = $ignoreStartDayOffset; + } + + public function setIgnoreRestrictions( bool $ignoreRestrictions ): void { + $this->ignoreRestrictions = $ignoreRestrictions; + } } diff --git a/src/Model/CustomPost.php b/src/Model/CustomPost.php index ec47fd928..9b47bd342 100644 --- a/src/Model/CustomPost.php +++ b/src/Model/CustomPost.php @@ -29,6 +29,13 @@ class CustomPost { */ protected $post; + /** + * The post ID of the WordPress post + * + * @var int + */ + protected int $ID; + /** * @var string */ @@ -49,6 +56,10 @@ public function __construct( $post ) { } else { throw new Exception( 'Invalid post param. Needed WP_Post or ID (int)' ); } + if ( ! $this->post instanceof WP_Post ) { + throw new Exception( 'Invalid post param. No post found for ID ' . $post ); + } + $this->ID = $this->post->ID; } /** diff --git a/src/Model/Day.php b/src/Model/Day.php index 72d0ec13f..4928b8e23 100644 --- a/src/Model/Day.php +++ b/src/Model/Day.php @@ -42,6 +42,17 @@ class Day { */ protected ?array $timeframes = null; + /** + * When this is enabled, restrictions are ignored when creating availabilities. + * This is useful when you want to differentiate between an item that is booked / not available + * and an item that would be bookable but is in repair. + * + * Used in @see \CommonsBooking\API\GBFS\VehicleStatus to differentiate between booked items and disabled items + * + * @var bool + */ + protected bool $ignoreRestrictions = false; + /** * Day constructor. * @@ -151,7 +162,7 @@ public function getTimeframes(): array { /** * Returns array with restrictions. * - * @return array + * @return Restriction[] * @throws Exception */ public function getRestrictions(): array { @@ -545,7 +556,7 @@ protected function removeEmptySlots( &$slots ) { * @throws Exception */ protected function getTimeframeSlots(): array { - $customCacheKey = $this->getDate() . serialize( $this->items ) . serialize( $this->locations ); + $customCacheKey = $this->getDate() . serialize( $this->items ) . serialize( $this->locations ) . serialize( $this->ignoreRestrictions ); $customCacheKey = md5( $customCacheKey ); $cacheItem = Plugin::getCacheItem( $customCacheKey ); if ( $cacheItem ) { @@ -566,7 +577,9 @@ protected function getTimeframeSlots(): array { } $this->mapTimeFrames( $slots ); - $this->mapRestrictions( $slots ); + if ( ! $this->ignoreRestrictions ) { + $this->mapRestrictions( $slots ); + } $this->sanitizeSlots( $slots ); Plugin::setCacheItem( @@ -602,4 +615,8 @@ protected function getSlotTimestampStart( $slotsPerDay, $slotNr ) { protected function getSlotTimestampEnd( $slotsPerDay, $slotNr ) { return strtotime( $this->getDate() ) + ( ( $slotNr + 1 ) * ( ( 24 / $slotsPerDay ) * 3600 ) ) - 1; } + + public function setIgnoreRestrictions( bool $ignoreRestrictions ): void { + $this->ignoreRestrictions = $ignoreRestrictions; + } } diff --git a/src/Model/Item.php b/src/Model/Item.php index 25aeae158..084be6bd1 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -4,6 +4,7 @@ namespace CommonsBooking\Model; use CommonsBooking\Helper\Helper; +use CommonsBooking\Helper\Wordpress; use CommonsBooking\Repository\Timeframe; use Exception; @@ -70,6 +71,7 @@ public function getAdmins() { * * This function is not used anywhere yet. * + * @deprecated since 2.11, removal in 2.12. * @return array * @throws Exception */ @@ -81,4 +83,159 @@ public function getRestrictions(): array { true ); } + + /** + * Will get a rotating ID by which the vehicle can be identified. + * The ID rotates after every trip and can be used to publish a vehicle ID to the GBFS API. + * + * The GBFS spec demands, that a vehicle ID must be rotated after each trip so that the users cannot be profiled. + * This needs to be deterministic and reversible. + * + * The ID should be reversible, so that we can get a deep link to the item that you found in the feed. + * + * Inspired by: https://tier.engineering/How-we-anonymize-user-trips-on-public-APIs + * Difference: We don't care about anonymity as much, because we don't offer A -> B trips. + * + * This function uses wp_hash to get a hashed identifier, this uses md5 hashing internally. + * + * @return string - a rotating ID for a vehicle + */ + public function getCloakedId(): string { + $closestBooking = $this->getClosestBooking(); + $secondHash = $closestBooking->post_name ?? $this->post_name; // If there is a booking, hash that. Otherwise, get the post name of the item as second hash item + + return wp_hash( $this->ID . $secondHash ); + } + + /** + * Gets the permalink for an item as a cloaked URL to be published in the API. + * + * @return string + */ + public function getCloakedURL(): string { + return add_query_arg( + array( + \CommonsBooking\Repository\Item::QUERY_VEHICLE_ID => $this->getCloakedId(), + \CommonsBooking\Repository\Item::URL_SLUG => true, + ), + get_site_url() . '/' + ); + } + + /** + * Gets the closest Booking for a given Item. + * + * @return ?Booking the booking that is past and closest to the current time, null if no booking is present + */ + public function getClosestBooking(): ?Booking { + + $location = $this->getLocation(); + if ( $location === null ) { + return null; + } + + $allBookings = \CommonsBooking\Repository\Booking::get( + [ $location->ID ], + [ $this->ID ], + null, + true, + null, + [ 'confirmed' ] + ); + + $allBookings = array_filter( $allBookings, fn( $b ) => $b->isPast() ); + + if ( empty( $allBookings ) ) { + return null; + } + + usort( + $allBookings, + function ( $a, $b ) { + $aStartDate = $a->getStartDate(); + $bStartDate = $b->getStartDate(); + + if ( $aStartDate == $bStartDate ) { + $aStartTimeDT = $a->getStartTimeDateTime(); + $bStartTimeDT = $b->getStartTimeDateTime(); + + return $aStartTimeDT <=> $bStartTimeDT; + } + + return $aStartDate <=> $bStartDate; + } + ); + + return array_pop( $allBookings ); + } + + /** + * Will get the location that the item is currently stationed at and bookable. + * Will take into account the current time, the item can have timeframes + * at multiple locations but can only be at one location at a time. + * + * @return ?Location will return null when no Location was found + */ + public function getLocation(): ?Location { + return $this->getClosestBookableTimeframe()?->getLocation();// why I used a deprecated method here: https://github.com/wielebenwir/commonsbooking/issues/507#issuecomment-4235848408 + } + + /** + * Will get the timeframe that is currently applicable for this item. + * When there are multiple timeframes, it wil select the closest. + * + * @return \CommonsBooking\Model\Timeframe|null + */ + public function getClosestBookableTimeframe(): ?\CommonsBooking\Model\Timeframe { + $locations = \CommonsBooking\Repository\Location::getByItem( $this->ID, true ); + + if ( empty( $locations ) ) { + return null; + } + + $timeframes = []; + foreach ( $locations as $location ) { + $timeframes = array_merge( + $timeframes, + $location->getBookableTimeframesByItem( $this->ID, true ) + ); + } + return \CommonsBooking\View\Calendar::getClosestBookableTimeFrameForToday( $timeframes ); + } + + /** + * Determines whether this item is currently free at a given location. + * Free is the opposite of rented. Checks against live availability slots, so it excludes items with Holiday + * Timeframes or overbooking-only availability, although they are technically not rented during these periods. + * + * This method will include items that may only be booked in advance (\CommonsBooking\Model\Timeframe::META_TIMEFRAME_ADVANCE_BOOKING_DAYS), + * because they are technically available at this location. Just not for pickup right now. + * + * @param int $locationId + * @param bool $ignoreStartDayOffset + * @param bool $ignoreRestrictions + * @return bool true if the item is free right now, false otherwise + * @throws Exception + */ + public function isCurrentlyFreeAtLocation( int $locationId, bool $ignoreStartDayOffset = false, bool $ignoreRestrictions = false ): bool { + $nowDT = Wordpress::getUTCDateTimeByTimestamp( current_time( 'timestamp' ) ); + $itemCalendar = new Calendar( + new Day( date( 'Y-m-d', strtotime( '-1 day' ) ) ), + new Day( date( 'Y-m-d', strtotime( '+1 day' ) ) ), + [ $locationId ], + [ $this->ID ] + ); + $itemCalendar->setIgnoreStartDayOffset( $ignoreStartDayOffset ); + $itemCalendar->setIgnoreRestrictions( $ignoreRestrictions ); + + foreach ( $itemCalendar->getAvailabilitySlots() as $availabilitySlot ) { + $startDT = new \DateTime( $availabilitySlot->start ); + $endDT = new \DateTime( $availabilitySlot->end ); + if ( $nowDT >= $startDT && $nowDT <= $endDT ) { + return true; + } + } + + return false; + } } diff --git a/src/Model/Location.php b/src/Model/Location.php index bc178aaf3..7a1139c93 100644 --- a/src/Model/Location.php +++ b/src/Model/Location.php @@ -258,6 +258,7 @@ public function getAdmins() { /** * Will get the currently applicable restrictions for the location. * + * @deprecated since 2.11, removal in 2.12 * @return Restriction[] * @throws \Exception */ diff --git a/src/Model/Restriction.php b/src/Model/Restriction.php index 80bd7cfbd..e6b8560a6 100644 --- a/src/Model/Restriction.php +++ b/src/Model/Restriction.php @@ -171,8 +171,9 @@ public function isActive(): bool { /** * Returns true if restriction ist active. - * TODO this function seems unused in restriction context. Check if it can be removed @markus-mw + * Unused in restriction context * + * @deprecated since 2.11, removal in 2.12 * @return bool */ public function isLocked(): bool { @@ -238,6 +239,9 @@ public function getEndDateDateTime(): DateTime { /** * Returns item name for the item that is restricted. * + * Unused: accessed through {{item:post_title}} template tag over Item Model, not this method + * + * @deprecated since 2.11, removal in 2.12 * @return string */ public function getItemName(): string { @@ -262,6 +266,9 @@ public function getItemId() { /** * Returns location name for the location that the restricted item is in. * + * Unused, can be accessed through {{location:post_title}} template tag, not needed here + * + * @deprecated since 2.11, removal in 2.12. * @return string */ public function getLocationName(): string { diff --git a/src/Model/Timeframe.php b/src/Model/Timeframe.php index 6b135ce72..79ad2c5e0 100644 --- a/src/Model/Timeframe.php +++ b/src/Model/Timeframe.php @@ -28,46 +28,119 @@ class Timeframe extends CustomPost { */ public const ERROR_TYPE = 'timeframeValidationFailed'; + /** + * The error type that occurs, when a timeframe has bookings that have been orphaned. through items changing locations. + * The user is notified about this, so that they can move the bookings using Service::MassOperations. + */ public const ORPHANED_TYPE = 'timeframehasOrphanedBookings'; + /** + * The metafield that stores the timestamp (int) for when the timeframe starts. + */ public const REPETITION_START = 'repetition-start'; + /** + * The metafield that stores the timestamp (int) for when the timeframe ends. + */ public const REPETITION_END = 'repetition-end'; + /** + * The meta field for what kind of selection type is used to select the item. + * Value is either one of self::SELECTION_MANUAL_ID , self::SELECTION_CATEGORY_ID or self::SELECTION_ALL_ID + */ public const META_ITEM_SELECTION_TYPE = 'item-select'; + /** + * The metafield for the item post id associated with the timeframe. + */ public const META_ITEM_ID = 'item-id'; + /** + * The metafield where a serialized array of post IDs (multiple) of items associated with the timeframe is stored + */ public const META_ITEM_ID_LIST = 'item-id-list'; + /** + * The metafield where a serialized array of term_ids that make up the categories from which the items associated with the timeframe are stored. + */ public const META_ITEM_CATEGORY_IDS = 'item-category-ids'; + /** + * The meta field for what kind of selection type is used to select the location. + * Value is either one of self::SELECTION_MANUAL_ID , self::SELECTION_CATEGORY_ID or self::SELECTION_ALL_ID + */ public const META_LOCATION_SELECTION_TYPE = 'location-select'; + /** + * The metafield for the location post id associated with the timeframe. + */ public const META_LOCATION_ID = 'location-id'; + /** + * The metafield where a serialized array of post IDs (multiple) of locations associated with the timeframe is stored + */ public const META_LOCATION_ID_LIST = 'location-id-list'; + /** + * The metafield where a serialized array of term_ids that make up the categories from which the locaations associated with the timeframe are stored. + */ public const META_LOCATION_CATEGORY_IDS = 'location-category-ids'; + /** + * Metafield for what type of repetition the timeframe uses. + * For possible values @see Timeframe::getRepetition() + */ public const META_REPETITION = 'timeframe-repetition'; + /** + * Metafield for how many days in advance the item on that timeframe can be booked. + * When this is limited to for example 30 days, only the next 30 days can be booked. + */ public const META_TIMEFRAME_ADVANCE_BOOKING_DAYS = 'timeframe-advance-booking-days'; + /** + * Metafield for the maximum length in days a booking on this timeframe may have. + */ public const META_MAX_DAYS = 'timeframe-max-days'; + /** + * A possible meta_value for META_ITEM_SELECTION_TYPE and META_LOCATION_SELECTION_TYPE + * This value implies, that posts are individually selected from a list of posts. + */ public const SELECTION_MANUAL_ID = 0; + /** + * A possible meta_value for META_ITEM_SELECTION_TYPE and META_LOCATION_SELECTION_TYPE + * This value implies, that the user selects a category of posts that the timeframe applies to. + */ public const SELECTION_CATEGORY_ID = 1; + /** + * A possible meta_value for META_ITEM_SELECTION_TYPE and META_LOCATION_SELECTION_TYPE + * This value implies, that the timeframe applies to all items / locations of the instance. + */ public const SELECTION_ALL_ID = 2; + /** + * A metafield with an on/off value determining if booking codes shall be created for the timeframe (only bookable timeframes). + */ public const META_CREATE_BOOKING_CODES = 'create-booking-codes'; + /** + * A metafield that defines how many days in advance the user HAS to book an item. This means, that the location often needs some kind of + * booking ahead, and that an item cannot be booked at the same day. Integer value in days. + */ public const META_BOOKING_START_DAY_OFFSET = 'booking-startday-offset'; + /** + * A metafield with an on/off value determining if the booking codes generated in the timeframe shall also be shown to the user. + */ public const META_SHOW_BOOKING_CODES = 'show-booking-codes'; + /** + * A metafield that stores a serialized array of strings with slugs of user roles that are allowed to book this item. When this is empty, + * all user roles may book this item. + */ public const META_ALLOWED_USER_ROLES = 'allowed_user_roles'; /** @@ -75,7 +148,10 @@ class Timeframe extends CustomPost { * Example: 2020-01-01,2020-01-02,2020-01-03 */ public const META_MANUAL_SELECTION = 'timeframe_manual_date'; - const MAX_DAYS_DEFAULT = 3; + /** + * The default value for self::META_MAX_DAYS. + */ + const MAX_DAYS_DEFAULT = 3; /** * null means the data is not fetched yet @@ -240,42 +316,43 @@ public function getLatestPossibleBookingDateTimestamp() { * This is used to display the end date of the timeframe in the frontend. * This is mainly in use by the [cb_items] shortcode. * - * @param int $startDate - * @param int $endDate + * @param int $startDate + * @param int|false $endDate false when timeframe is open ended * * @return string */ - public static function formatBookableDate( int $startDate, int $endDate ): string { + public static function formatBookableDate( int $startDate, $endDate ): string { $format = self::getDateFormat(); $today = strtotime( 'now' ); $startDateFormatted = date_i18n( $format, $startDate ); - $endDateFormatted = date_i18n( $format, $endDate ); + $endDateFormatted = $endDate !== false ? date_i18n( $format, $endDate ) : ''; $label = commonsbooking_sanitizeHTML( __( 'Available here', 'commonsbooking' ) ); $availableString = ''; - if ( $startDate && $endDate && $startDate === $endDate ) { // available only one day - /* translators: %s = date in WordPress defined format */ - $availableString = sprintf( commonsbooking_sanitizeHTML( __( 'on %s', 'commonsbooking' ) ), $startDateFormatted ); - } elseif ( $startDate && ! $endDate ) { // start but no end date - if ( $startDate > $today ) { // start is in the future - $availableString = sprintf( - /* translators: %s = date in WordPress defined format */ - commonsbooking_sanitizeHTML( __( 'from %s', 'commonsbooking' ) ), - $startDateFormatted - ); - } else { // start has passed, no end date, probably a fixed location - $availableString = commonsbooking_sanitizeHTML( __( 'permanently', 'commonsbooking' ) ); - } - } elseif ( $startDate && $endDate ) { // start AND end date - if ( $startDate > $today ) { // start is in the future, with an end date - $availableString = sprintf( - /* translators: %1$s = startdate, second %2$s = enddate in WordPress defined format */ - commonsbooking_sanitizeHTML( __( 'from %1$s until %2$s', 'commonsbooking' ) ), - $startDateFormatted, - $endDateFormatted - ); + if ( $startDate !== 0 ) { + if ( $endDate === false ) { // start but no end date + if ( $startDate > $today ) { // start is in the future + $availableString = sprintf( + /* translators: %s = date in WordPress defined format */ + commonsbooking_sanitizeHTML( __( 'from %s', 'commonsbooking' ) ), + $startDateFormatted + ); + } else { // start has passed, no end date, probably a fixed location + $availableString = commonsbooking_sanitizeHTML( __( 'permanently', 'commonsbooking' ) ); + } + } elseif ( $startDate === $endDate ) { // available only one day + /* translators: %s = date in WordPress defined format */ + $availableString = sprintf( commonsbooking_sanitizeHTML( __( 'on %s', 'commonsbooking' ) ), $startDateFormatted ); + } elseif ( $startDate > $today ) { // start AND end date + // start is in the future, with an end date + $availableString = sprintf( + /* translators: %1$s = startdate, second %2$s = enddate in WordPress defined format */ + commonsbooking_sanitizeHTML( __( 'from %1$s until %2$s', 'commonsbooking' ) ), + $startDateFormatted, + $endDateFormatted + ); } else { // start has passed, with an end date $availableString = sprintf( /* translators: %s = enddate in WordPress defined format */ @@ -1023,15 +1100,6 @@ public function usesBookingCodes(): bool { return $this->getMeta( self::META_CREATE_BOOKING_CODES ) == 'on'; } - /** - * Returns true if booking codes were enabled for this timeframe - * - * @return bool - */ - public function hasBookingCodes(): bool { - return $this->getMeta( 'create-booking-codes' ) == 'on'; - } - /** * Returns repetition-start \DateTime. * This function contains a weird hotfix for full day timeframes. diff --git a/src/Plugin.php b/src/Plugin.php index b7e143506..d835e617d 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -5,6 +5,7 @@ use CommonsBooking\CB\CB1UserFields; use CommonsBooking\Exception\BookingDeniedException; +use CommonsBooking\Helper\Feature; use CommonsBooking\Helper\Wordpress; use CommonsBooking\Map\LocationMapAdmin; use CommonsBooking\Map\SearchShortcode; @@ -384,7 +385,7 @@ public static function addMenuPages() { esc_html__( 'Item Categories', 'commonsbooking' ), esc_html__( 'Item Categories', 'commonsbooking' ), 'manage_' . COMMONSBOOKING_PLUGIN_SLUG, - admin_url( 'edit-tags.php' ) . '?taxonomy=' . Item::getTaxonomyName(), + admin_url( 'edit-tags.php' ) . '?taxonomy=' . Item::getTaxonomyName() . '&post_type=' . Item::getPostType(), '' ); @@ -394,7 +395,7 @@ public static function addMenuPages() { esc_html__( 'Location Categories', 'commonsbooking' ), esc_html__( 'Location Categories', 'commonsbooking' ), 'manage_' . COMMONSBOOKING_PLUGIN_SLUG, - admin_url( 'edit-tags.php' ) . '?taxonomy=' . Location::getTaxonomyName(), + admin_url( 'edit-tags.php' ) . '?taxonomy=' . Location::getTaxonomyName() . '&post_type=' . Location::getPostType(), '' ); @@ -831,6 +832,9 @@ function () { // iCal rewrite iCalendar::initRewrite(); + + // permalink resolution rewrite + \CommonsBooking\Repository\Item::initRewrite(); } /** @@ -901,26 +905,45 @@ public static function getCustomPostTypesLabels(): array { */ public function initRoutes() { // Check if API is activated in settings - $api_activated = Settings::getOption( 'commonsbooking_options_api', 'api-activated' ); - if ( $api_activated != 'on' ) { + if ( ! Feature::isApiEnabled() ) { return false; } add_action( 'rest_api_init', function () { - $routes = [ - new \CommonsBooking\API\AvailabilityRoute(), - new \CommonsBooking\API\ItemsRoute(), - new \CommonsBooking\API\LocationsRoute(), - // new \CommonsBooking\API\OwnersRoute(), - new \CommonsBooking\API\ProjectsRoute(), - new \CommonsBooking\API\GBFS\Discovery(), - new \CommonsBooking\API\GBFS\StationInformation(), - new \CommonsBooking\API\GBFS\StationStatus(), - new \CommonsBooking\API\GBFS\SystemInformation(), - - ]; + $routes = []; + + // Commons API routes + if ( Feature::isCommonsApiEnabled() ) { + $routes = array_merge( + $routes, + [ + new \CommonsBooking\API\AvailabilityRoute(), + new \CommonsBooking\API\ItemsRoute(), + new \CommonsBooking\API\LocationsRoute(), + // new \CommonsBooking\API\OwnersRoute(), + new \CommonsBooking\API\ProjectsRoute(), + ] + ); + } + + // GBFS API routes + if ( Feature::isGbfsEnabled() ) { + $routes = array_merge( + $routes, + [ + new \CommonsBooking\API\GBFS\Discovery(), + new \CommonsBooking\API\GBFS\StationInformation(), + new \CommonsBooking\API\GBFS\StationStatus(), + new \CommonsBooking\API\GBFS\VehicleAvailability(), + new \CommonsBooking\API\GBFS\VehicleStatus(), + new \CommonsBooking\API\GBFS\VehicleTypes(), + new \CommonsBooking\API\GBFS\SystemInformation(), + ] + ); + } + foreach ( $routes as $route ) { $route->register_routes(); } diff --git a/src/Repository/BookablePost.php b/src/Repository/BookablePost.php index 924eed4a6..a0203edce 100644 --- a/src/Repository/BookablePost.php +++ b/src/Repository/BookablePost.php @@ -217,9 +217,9 @@ abstract protected static function getModelClass(); * @param array $args WP Post args * @param bool $bookable * - * @return array + * @return \CommonsBooking\Model\Location[]|\CommonsBooking\Model\Item[] */ - public static function get( array $args = array(), bool $bookable = false ) { + public static function get( array $args = array(), bool $bookable = false ): array { $posts = []; $args['post_type'] = static::getPostType(); $args['nopaging'] = true; @@ -273,7 +273,7 @@ public static function get( array $args = array(), bool $bookable = false ) { * @param $relatedType * @param bool $bookable * - * @return int[] Array of post ids + * @return \CommonsBooking\Model\Location[] | \CommonsBooking\Model\Item[] * @throws Exception */ protected static function getByRelatedPost( $postId, $originType, $relatedType, bool $bookable = false ): array { diff --git a/src/Repository/Booking.php b/src/Repository/Booking.php index 2fb725d54..a85394379 100644 --- a/src/Repository/Booking.php +++ b/src/Repository/Booking.php @@ -351,8 +351,8 @@ public static function getForCurrentUser( * Returns bookings. This uses the CommonsBooking\Repository\Timeframe::get() method which * is not based on the WP_Query class but will perform its own SQL query. * - * @param array $locations - * @param array $items + * @param array $locations an array of post IDs + * @param array $items an array of post IDs * @param string|null $date Date-String in format YYYY-mm-dd * @param bool $returnAsModel if true, returns booking model, if false return int array (defaults to false) * @param int|null $minTimestamp diff --git a/src/Repository/CB1.php b/src/Repository/CB1.php index 0b519ada2..024e4afe7 100644 --- a/src/Repository/CB1.php +++ b/src/Repository/CB1.php @@ -9,6 +9,8 @@ * This class contains methods to query the database for old CB1 data. * CB1 is CommonsBooking up to version 0.9.4.18 (https://wordpress.org/plugins/commons-booking/) * This class is mainly used to migrate over the old data to CB2. + * + * @deprecated since 2.11 , removal in 2.12 */ class CB1 { @@ -234,10 +236,10 @@ public static function getCB2PostIdByCB1Id( $id ): ?int { $table_postmeta = $wpdb->prefix . 'postmeta'; $sql = $wpdb->prepare( - "SELECT meta_value as cb1_id, post_id as cb2_id + "SELECT meta_value as cb1_id, post_id as cb2_id FROM $table_postmeta WHERE - meta_key = '_cb_cb1_post_post_ID' AND + meta_key = '_cb_cb1_post_post_ID' AND meta_value = %s; ", $id @@ -266,10 +268,10 @@ public static function getCB1Taxonomies() { return $wpdb->get_results( " SELECT - tr.*, + tr.*, tt.taxonomy, t.slug as term - FROM $table_term_relationships tr + FROM $table_term_relationships tr LEFT JOIN $table_term_taxonomy tt ON tr.term_taxonomy_id = tt.term_id LEFT JOIN $table_terms t ON diff --git a/src/Repository/Item.php b/src/Repository/Item.php index ada54a228..9629ac961 100644 --- a/src/Repository/Item.php +++ b/src/Repository/Item.php @@ -5,6 +5,8 @@ use Exception; class Item extends BookablePost { + public const URL_SLUG = COMMONSBOOKING_PLUGIN_SLUG . '_get_vehicle'; + public const QUERY_VEHICLE_ID = COMMONSBOOKING_PLUGIN_SLUG . '_vehicle_cloaked_id'; /** * Returns array with items at location based on bookable timeframes. @@ -20,6 +22,50 @@ public static function getByLocation( $locationId, bool $bookable = false ): arr return self::getByRelatedPost( $locationId, 'location', 'item', $bookable ); } + /** + * Allows resolving cloaked vehicle IDs published by the GBFS API back to the corresponding items + * + * @return void + */ + public static function initRewrite() { + add_action( + 'wp_loaded', + function () { + add_rewrite_rule( self::URL_SLUG, 'index.php?' . self::URL_SLUG . '=1', 'top' ); + } + ); + + add_filter( + 'query_vars', + function ( $query_vars ) { + $query_vars[] = self::URL_SLUG; + return $query_vars; + } + ); + + add_action( + 'parse_request', + function ( &$wp ) { + + if ( + ! array_key_exists( self::URL_SLUG, $wp->query_vars ) || + ! isset( $_GET[ self::QUERY_VEHICLE_ID ] ) || + empty( $_GET[ self::QUERY_VEHICLE_ID ] ) + ) { + return; + } + $cloakedId = sanitize_text_field( wp_unslash( $_GET[ self::QUERY_VEHICLE_ID ] ) ); + $item = Item::getByCloakedId( $cloakedId ); + if ( $item === null ) { + die( 'invalid vehicle id' ); + } + $url = get_permalink( $item->ID ); + wp_redirect( $url ); + exit; + } + ); + } + /** * @return string */ @@ -27,6 +73,22 @@ protected static function getPostType(): string { return \CommonsBooking\Wordpress\CustomPostType\Item::getPostType(); } + /** + * Gets an individual item from a cloaked ID. The GBFS API uses this to provide + * deep-links with rotating vehicle IDs. + * + * @param string $cloakedId + * @return \CommonsBooking\Model\Item|null + */ + public static function getByCloakedId( string $cloakedId ): ?\CommonsBooking\Model\Item { + foreach ( self::get() as $item ) { + if ( $item->getCloakedId() == $cloakedId ) { + return $item; + } + } + return null; + } + /** * This is the model class that belongs to the post type. * With the model class, you are able to perform additional functions on the post type. diff --git a/src/Repository/Location.php b/src/Repository/Location.php index ae3b881c1..3f448c461 100644 --- a/src/Repository/Location.php +++ b/src/Repository/Location.php @@ -13,7 +13,7 @@ class Location extends BookablePost { * * @param bool $bookable * - * @return array + * @return \CommonsBooking\Model\Location[] * @throws Exception */ public static function getByItem( $itemId, bool $bookable = false ): array { diff --git a/src/Repository/PostRepository.php b/src/Repository/PostRepository.php index 16135751a..e8a73b2f7 100644 --- a/src/Repository/PostRepository.php +++ b/src/Repository/PostRepository.php @@ -57,4 +57,6 @@ public static function getPostById( $postId ) { return $post; } } + + abstract public static function get( array $args = array() ): array; } diff --git a/src/Service/BookingRule.php b/src/Service/BookingRule.php index bbe26f427..47299519c 100644 --- a/src/Service/BookingRule.php +++ b/src/Service/BookingRule.php @@ -443,7 +443,7 @@ public static function checkMaxBookingDays( Booking $booking, array $args, $appl $allowedBookedDays = $args[0]; $periodDays = $args[1]; // split the period in half, when it is an uneven number, the left side will be one day longer - $daysHalf = $periodDays / 2; + $daysHalf = floor( $periodDays / 2 ); if ( $periodDays % 2 ) { $daysLeft = $daysHalf + 1; $daysRight = $daysHalf - 1; diff --git a/src/Service/BookingRuleApplied.php b/src/Service/BookingRuleApplied.php index a9db1e2b6..5335cfd00 100644 --- a/src/Service/BookingRuleApplied.php +++ b/src/Service/BookingRuleApplied.php @@ -42,8 +42,8 @@ public function __construct( BookingRule $rule ) { $rule->description, $rule->errorMessage, $rule->validationFunction, - $rule->params ?? [], - $rule->selectParam ?? [], + empty( $rule->params ) ? [] : $rule->params, + empty( $rule->selectParam ) ? [] : $rule->selectParam, $rule->errorFromArgs ?? null ); } diff --git a/src/View/Booking.php b/src/View/Booking.php index 0c3ded1dc..2bdfa4124 100755 --- a/src/View/Booking.php +++ b/src/View/Booking.php @@ -344,9 +344,15 @@ public static function getLocationForItem_AJAX() { try { $itemModel = new \CommonsBooking\Model\Item( $itemID ); - $location = \CommonsBooking\Repository\Location::getByItem( $itemID, true ); - // pick the first location, no matter what - $location = reset( $location ); + $location = $itemModel->getLocation(); + if ( ! $location ) { + // This won't be displayed anywhere + wp_send_json_error( + array( + 'message' => 'No location found for this item.', + ) + ); + } $timeframe = Timeframe::getBookable( [ $location->ID ], [ $itemID ], @@ -363,22 +369,13 @@ public static function getLocationForItem_AJAX() { ) ); } - if ( $location ) { - wp_send_json( - array( - 'success' => true, - 'locationID' => $location->ID, - 'fullDay' => $timeframe->isFullDay(), - ) - ); - } else { - // This won't be displayed anywhere - wp_send_json_error( - array( - 'message' => 'No location found for this item.', - ) - ); - } + wp_send_json( + array( + 'success' => true, + 'locationID' => $location->ID, + 'fullDay' => $timeframe->isFullDay(), + ) + ); } /** diff --git a/src/View/BookingCodes.php b/src/View/BookingCodes.php index 02a1b917d..96ce87764 100644 --- a/src/View/BookingCodes.php +++ b/src/View/BookingCodes.php @@ -181,7 +181,7 @@ public static function renderCronEmailFields( $field, $escaped_value, $object_id __( 'Unable to send Emails. No location email(s) configured, check location', 'commonsbooking' ) . sprintf( ' %s', esc_url( get_edit_post_link( $location->ID ) ), commonsbooking_sanitizeHTML( $location->post_title ) ) ); - } elseif ( ! $timeframe->hasBookingCodes() ) { + } elseif ( ! $timeframe->usesBookingCodes() ) { $errMsg = commonsbooking_sanitizeHTML( __( 'This timeframe has no booking codes. To generate booking codes you need to save the timeframe.', 'commonsbooking' ) ); } @@ -290,7 +290,7 @@ public static function renderDirectEmailRow( $field_args, $field ) { __( 'Unable to send Emails. No location email(s) configured, check location', 'commonsbooking' ) . sprintf( ' %s', esc_url( get_edit_post_link( $location->ID ) ), commonsbooking_sanitizeHTML( $location->post_title ) ) ); - } elseif ( ! $timeframe->hasBookingCodes() ) { + } elseif ( ! $timeframe->usesBookingCodes() ) { echo commonsbooking_sanitizeHTML( __( 'This timeframe has no booking codes. To generate booking codes you need to save the timeframe.', 'commonsbooking' ) ); } else { echo ' @@ -386,7 +386,7 @@ public static function renderTable( $timeframeId ) {
-
' . ( $timeframe->hasBookingCodes() ? ' +
' . ( $timeframe->usesBookingCodes() ? ' Download booking codes

' . @@ -410,7 +410,7 @@ public static function renderTable( $timeframeId ) {

'; - if ( $timeframe->hasBookingCodes() ) { + if ( $timeframe->usesBookingCodes() ) { echo self::renderTableFor( 'timeframe_form', $bookingCodes ); echo '
'; @@ -547,7 +547,6 @@ function ( $action, $result ) use ( $timeframeId ) { 2 ); - // @phpstan-ignore deadCode.unreachable (false positive, covered by unit tests) $booking_msg = new BookingCodesMessage( $timeframeId, 'codes', $tsFrom, $tsTo ); $booking_msg->sendMessage(); diff --git a/src/View/Calendar.php b/src/View/Calendar.php index dba371928..833b50b6e 100644 --- a/src/View/Calendar.php +++ b/src/View/Calendar.php @@ -147,7 +147,11 @@ public static function renderTable( $atts ): string { $locations = []; foreach ( $timeframes as $timeframe ) { // TODO #507 - $locations[ $timeframe->getLocationID() ] = $timeframe->getLocation()->post_title; + $location = $timeframe->getLocation(); + if ( ! $location ) { + continue; + } + $locations[ $location->ID ] = $location->post_title; } // loop through location diff --git a/src/Wordpress/CustomPostType/Booking.php b/src/Wordpress/CustomPostType/Booking.php index 2d92d7e77..c04cc194c 100644 --- a/src/Wordpress/CustomPostType/Booking.php +++ b/src/Wordpress/CustomPostType/Booking.php @@ -291,6 +291,19 @@ public static function handleBookingRequest( throw new BookingDeniedException( __( 'There is already a booking in this time-range. This notice may also appear if there is an unconfirmed booking in the requested period. Unconfirmed bookings are deleted after about 10 minutes. Please try again in a few minutes.', 'commonsbooking' ) ); } + // The initial calendar flow always submits post_status=unconfirmed without a post_ID. + // If an exact-slot booking already exists for the current user, redirect to that booking + // instead of downgrading it back to unconfirmed via the update path below. + if ( $booking && $post_status === 'unconfirmed' && $post_ID === null ) { + return $booking->ID; + } + + // Frontend requests should never reopen an existing booking as unconfirmed by ID. + // Treat this as an invalid request instead of mutating the current booking state. + if ( $post_status === 'unconfirmed' && $post_ID !== null ) { + throw new BookingDeniedException( __( 'Invalid booking request. Please try again.', 'commonsbooking' ) ); + } + $existingBookings = \CommonsBooking\Repository\Booking::getExistingBookings( $itemId, @@ -316,7 +329,7 @@ public static function handleBookingRequest( array_values( $existingBookings )[0]->getPost()->post_name === $requestedPostName && intval( array_values( $existingBookings )[0]->getPost()->post_author ) === get_current_user_id(); - if ( ( ! $isEdit || count( $existingBookings ) > 1 ) && $post_status !== 'canceled' ) { + if ( ! $isEdit && $post_status !== 'canceled' ) { if ( $booking ) { $post_status = 'unconfirmed'; } else { @@ -749,7 +762,7 @@ protected function getCustomFields() {
  • Click on the Submit booking button at the end of the page to submit a new booking.
  • Please note: Only a few basic checks against existing bookings are performed. Please be wary of overlapping bookings. -

    +

    ', 'commonsbooking' ) . '

    ' @@ -890,7 +903,7 @@ public function displayBookingsAdminListNotice() { As an admin you can create bookings via this admin interface. Please be aware that admin bookings are not validated and checked. Use this function with care.
    Click on preview to show booking details in frontend
    - To search and filter bookings please integrate the frontend booking list via shortcode. + To search and filter bookings please integrate the frontend booking list via shortcode. See here %1$sHow to display the booking list%2$s', 'commonsbooking' ), diff --git a/src/Wordpress/CustomPostType/Item.php b/src/Wordpress/CustomPostType/Item.php index d29cb0eae..aee7a48d7 100644 --- a/src/Wordpress/CustomPostType/Item.php +++ b/src/Wordpress/CustomPostType/Item.php @@ -2,6 +2,7 @@ namespace CommonsBooking\Wordpress\CustomPostType; +use CommonsBooking\Helper\Feature; use CommonsBooking\Repository\UserRepository; use CommonsBooking\Settings\Settings; @@ -280,6 +281,20 @@ public function registerMetabox() { 'show_on_cb' => 'cmb2_hide_if_no_cats', // function should return a bool value ) ); + + // checkbox if item should be excluded from API shares + // only shown when the API is globally activated in the settings + $cmb->add_field( + array( + 'name' => esc_html__( 'Exclude from API', 'commonsbooking' ), + 'desc' => esc_html__( 'When this box is checked, the item will not appear in any of the API shares.', 'commonsbooking' ), + 'id' => MetaField::ItemApiExclude->getFieldId(), + 'type' => 'checkbox', + 'show_on_cb' => function () { + return Feature::isApiEnabled(); + }, + ) + ); } // Check if custom meta fields are set in CB Options and generate MetaData-Box and fields diff --git a/src/Wordpress/CustomPostType/MetaField.php b/src/Wordpress/CustomPostType/MetaField.php new file mode 100644 index 000000000..58c644fff --- /dev/null +++ b/src/Wordpress/CustomPostType/MetaField.php @@ -0,0 +1,29 @@ +value; + } +} diff --git a/src/Wordpress/CustomPostType/Restriction.php b/src/Wordpress/CustomPostType/Restriction.php index 9996acd06..2ce2818e6 100644 --- a/src/Wordpress/CustomPostType/Restriction.php +++ b/src/Wordpress/CustomPostType/Restriction.php @@ -159,31 +159,13 @@ public function setCustomColumnsData( $column, $post_id ) { echo '-'; break; case \CommonsBooking\Model\Restriction::META_TYPE: - $output = '-'; - - foreach ( $this->getCustomFields() as $customField ) { - if ( $customField['id'] == \CommonsBooking\Model\Restriction::META_TYPE ) { - foreach ( $customField['options'] as $key => $label ) { - if ( $value == $key ) { - $output = $label; - } - } - } - } + $types = self::getTypes(); + $output = $types[ $value ] ?? '-'; echo commonsbooking_sanitizeHTML( $output ); break; case \CommonsBooking\Model\Restriction::META_STATE: - $output = '-'; - - foreach ( $this->getCustomFields() as $customField ) { - if ( $customField['id'] == \CommonsBooking\Model\Restriction::META_STATE ) { - foreach ( $customField['options'] as $key => $label ) { - if ( $value == $key ) { - $output = $label; - } - } - } - } + $states = self::getStates(); + $output = $states[ $value ] ?? '-'; echo commonsbooking_sanitizeHTML( $output ); break; case \CommonsBooking\Model\Restriction::META_START: diff --git a/src/Wordpress/CustomPostType/Timeframe.php b/src/Wordpress/CustomPostType/Timeframe.php index d20f8571f..b6bc88ac4 100644 --- a/src/Wordpress/CustomPostType/Timeframe.php +++ b/src/Wordpress/CustomPostType/Timeframe.php @@ -1115,7 +1115,7 @@ public static function removeIrrelevantPostmeta( \CommonsBooking\Model\Timeframe \CommonsBooking\Model\Timeframe::META_SHOW_BOOKING_CODES, ]; // remove multi-select postmeta if not relevant (#507) - $onlyRelevantForHolidays = [ + $onlyRelevantForHolidaysOrRepair = [ \CommonsBooking\Model\Timeframe::META_ITEM_ID_LIST, \CommonsBooking\Model\Timeframe::META_LOCATION_ID_LIST, \CommonsBooking\Model\Timeframe::META_ITEM_CATEGORY_IDS, @@ -1124,14 +1124,15 @@ public static function removeIrrelevantPostmeta( \CommonsBooking\Model\Timeframe \CommonsBooking\Model\Timeframe::META_LOCATION_SELECTION_TYPE, ]; - if ( $timeframe->getType() != self::BOOKABLE_ID ) { + $type = $timeframe->getType(); + if ( $type !== self::BOOKABLE_ID ) { foreach ( $onlyRelevantForBookable as $metaKey ) { delete_post_meta( $timeframe->ID, $metaKey ); } } - if ( $timeframe->getType() != self::HOLIDAYS_ID ) { - foreach ( $onlyRelevantForHolidays as $metaKey ) { + if ( ! ( $type === self::HOLIDAYS_ID || $type === self::REPAIR_ID ) ) { + foreach ( $onlyRelevantForHolidaysOrRepair as $metaKey ) { delete_post_meta( $timeframe->ID, $metaKey ); } // reset to manual selection diff --git a/tests/cypress/e2e/02-litepicker-overbooking.cy.js b/tests/cypress/e2e/02-litepicker-overbooking.cy.js index e1d975b6e..ff19df689 100644 --- a/tests/cypress/e2e/02-litepicker-overbooking.cy.js +++ b/tests/cypress/e2e/02-litepicker-overbooking.cy.js @@ -18,7 +18,7 @@ describe('test overbooking process', () => { function updatePostMetaAndReload(postID, metaKey, metaValue) { cy.exec( - 'npx wp-env run tests-cli wp post meta update ' + + 'npx wp-env --config=.wp-env.test.json run cli wp post meta update ' + postID + ' ' + metaKey + diff --git a/tests/cypress/wordpress-files/e2e-override.json b/tests/cypress/wordpress-files/e2e-override.json index 8127d5ca2..7b08cdb57 100644 --- a/tests/cypress/wordpress-files/e2e-override.json +++ b/tests/cypress/wordpress-files/e2e-override.json @@ -8,12 +8,8 @@ "themes": [ "flegfleg/kasimir-theme" ], - "env": { - "tests": { - "mappings": { - "wp-content/plugins/commonsbooking": "./build/commonsbooking", - "wp-content/plugins/commonsbooking/tests/cypress/wordpress-files": "./tests/cypress/wordpress-files" - } - } + "mappings": { + "wp-content/plugins/commonsbooking": "./build/commonsbooking", + "wp-content/plugins/commonsbooking/tests/cypress/wordpress-files": "./tests/cypress/wordpress-files" } } diff --git a/tests/php/API/AvailabilityRouteTest.php b/tests/php/API/AvailabilityRouteTest.php index 475ee313f..3697d7396 100644 --- a/tests/php/API/AvailabilityRouteTest.php +++ b/tests/php/API/AvailabilityRouteTest.php @@ -43,11 +43,15 @@ public function testsAvailabilitySuccess() { $this->assertSame( 200, $response->get_status() ); $this->assertSame( 2, count( $response->get_data()->availability ) ); + $availabilityStart = new \DateTime( self::CURRENT_DATE ); + $availabilityEnd = new \DateTime( self::CURRENT_DATE ); + $availabilityEnd->modify( '23:59:59' ); + // Checks availability for the first day $this->assertEquals( $this->locationId, $response->get_data()->availability[0]->locationId ); $this->assertEquals( $this->itemId, $response->get_data()->availability[0]->itemId ); - $this->assertEquals( self::CURRENT_DATE . 'T00:00:00+00:00', $response->get_data()->availability[0]->start ); - $this->assertEquals( self::CURRENT_DATE . 'T23:59:59+00:00', $response->get_data()->availability[0]->end ); + $this->assertEquals( $availabilityStart->format( 'c' ), $response->get_data()->availability[0]->start ); + $this->assertEquals( $availabilityEnd->format( 'c' ), $response->get_data()->availability[0]->end ); ClockMock::reset(); } diff --git a/tests/php/API/CB_REST_Route_UnitTestCase.php b/tests/php/API/CB_REST_Route_UnitTestCase.php index 8292e463b..02ab5b103 100644 --- a/tests/php/API/CB_REST_Route_UnitTestCase.php +++ b/tests/php/API/CB_REST_Route_UnitTestCase.php @@ -3,6 +3,7 @@ namespace CommonsBooking\Tests\API; use CommonsBooking\Tests\CPTCreationTrait; +use CommonsBooking\Tests\Wordpress\CustomPostTypeTest; /** * Abstract test case which implicitly tests REST Routes @@ -12,7 +13,7 @@ class CB_REST_Route_UnitTestCase extends CB_REST_UnitTestCase { use CPTCreationTrait; - const CURRENT_DATE = '2021-05-21'; + const CURRENT_DATE = CustomPostTypeTest::CURRENT_DATE; protected $ENDPOINT; diff --git a/tests/php/API/GBFS/DiscoveryRouteTest.php b/tests/php/API/GBFS/DiscoveryRouteTest.php index dea527f80..28a9cb075 100644 --- a/tests/php/API/GBFS/DiscoveryRouteTest.php +++ b/tests/php/API/GBFS/DiscoveryRouteTest.php @@ -4,10 +4,25 @@ use CommonsBooking\Tests\API\CB_REST_Route_UnitTestCase; -/** - * TODO: add result unit test - */ class DiscoveryRouteTest extends CB_REST_Route_UnitTestCase { protected $ENDPOINT = '/commonsbooking/v1/gbfs.json'; + + public function testRoute() { + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + + $this->assertSame( 200, $response->get_status() ); + $data = $response->get_data()->data; + $this->assertNotEmpty( $data->feeds ); + $this->assertIsArray( $data->feeds ); + + $header = $response->get_data(); // the top level info that is always present + + $this->assertNotFalse( \DateTime::createFromFormat( \DateTime::ATOM, $header->last_updated ) ); + $this->assertIsInt( $header->ttl ); + $this->assertIsString( $header->version ); + + parent::testRoute(); + } } diff --git a/tests/php/API/GBFS/StationInformationRouteTest.php b/tests/php/API/GBFS/StationInformationRouteTest.php index fd9bd65d8..cc370ec56 100644 --- a/tests/php/API/GBFS/StationInformationRouteTest.php +++ b/tests/php/API/GBFS/StationInformationRouteTest.php @@ -3,11 +3,84 @@ namespace CommonsBooking\Tests\API\GBFS; use CommonsBooking\Tests\API\CB_REST_Route_UnitTestCase; +use CommonsBooking\Tests\Helper\GeoHelperTest; +use WP_REST_Request; -/** - * TODO: add result unit test - */ class StationInformationRouteTest extends CB_REST_Route_UnitTestCase { protected $ENDPOINT = '/commonsbooking/v1/station_information.json'; + + public function testBasicStationInformation_withLatLonMeta() { + update_post_meta( $this->locationId, 'geo_latitude', '50.123' ); + update_post_meta( $this->locationId, 'geo_longitude', '8.123' ); + + $request = new WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + + $this->assertSame( 200, $response->get_status() ); + + $data = $response->get_data()->data; + $this->assertNotEmpty( $data->stations ); + $this->assertCount( 1, $data->stations ); + + $station = $data->stations[0]; + + $this->assertEquals( (string) $this->locationId, $station->station_id ); + $this->assertNotEmpty( $station->name ); + $this->assertNotEmpty( $station->rental_uris->web ); + + $this->assertEquals( 50.123, $station->lat ); + $this->assertEquals( 8.123, $station->lon ); + } + + public function testTitleHtmlEntitiesAreDecoded() { + update_post_meta( $this->locationId, 'geo_latitude', '50.123' ); + update_post_meta( $this->locationId, 'geo_longitude', '8.123' ); + + wp_update_post( + [ + 'ID' => $this->locationId, + 'post_title' => 'Station & Hof', + ] + ); + + // Sanity check: WordPress stores the title with the encoded entity. + $this->assertStringContainsString( '&', get_post( $this->locationId )->post_title ); + + $request = new WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + + $this->assertSame( 200, $response->get_status() ); + + $station = $response->get_data()->data->stations[0]; + $this->assertEquals( 'Station & Hof', $station->name[0]->text ); + } + + // no gps data and no address defined, skip location + public function testStationInformation_geocodingNonExistent() { + delete_post_meta( $this->locationId, 'geo_latitude' ); + delete_post_meta( $this->locationId, 'geo_longitude' ); + + $mockedLocationCoordinates = GeoHelperTest::mockedLocation()->getCoordinates(); + + $request = new WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + + $data = $response->get_data()->data; + $this->assertEmpty( $data->stations ); + } + + public function setUp(): void { + parent::setUp(); + + $this->locationId = $this->createLocation( 'Test Location', 'publish' ); + $this->itemId = $this->createItem( 'TestItem', 'publish' ); + + $this->createTimeframe( + $this->locationId, + $this->itemId, + strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ), + strtotime( '+10 days', strtotime( self::CURRENT_DATE ) ) + ); + } } diff --git a/tests/php/API/GBFS/StationStatusRouteTest.php b/tests/php/API/GBFS/StationStatusRouteTest.php index 12fb49807..6d59a174e 100644 --- a/tests/php/API/GBFS/StationStatusRouteTest.php +++ b/tests/php/API/GBFS/StationStatusRouteTest.php @@ -2,12 +2,161 @@ namespace CommonsBooking\Tests\API\GBFS; +use CommonsBooking\Model\Restriction; use CommonsBooking\Tests\API\CB_REST_Route_UnitTestCase; +use CommonsBooking\Tests\Wordpress\CustomPostTypeTest; +use SlopeIt\ClockMock\ClockMock; -/** - * TODO: add result unit test - */ class StationStatusRouteTest extends CB_REST_Route_UnitTestCase { protected $ENDPOINT = '/commonsbooking/v1/station_status.json'; + public function testBasicStationStatus() { + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + + $this->assertSame( 200, $response->get_status() ); + + $data = $response->get_data()->data; + + $this->assertNotEmpty( $data->stations ); + $this->assertCount( 1, $data->stations ); + + $station = $data->stations[0]; + + $this->assertEquals( (string) $this->locationId, $station->station_id ); + $this->assertEquals( 1, $station->num_vehicles_available ); + $this->assertTrue( $station->is_installed ); + $this->assertTrue( $station->is_renting ); + $this->assertTrue( $station->is_returning ); + + $reported = new \DateTime( $station->last_reported ); + $now = new \DateTime( self::CURRENT_DATE ); + + $this->assertEqualsWithDelta( $now->getTimestamp(), $reported->getTimestamp(), 1.0 ); + } + + public function testStationStatus_whenBooked_isEmpty() { + $booking = $this->createConfirmedBookingStartingToday(); + + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + + $data = $response->get_data()->data; + $station = $data->stations[0]; + + $this->assertEquals( 0, $station->num_vehicles_available ); + } + + public function testStationStatus_afterTimeframeEnd_isEmpty() { + $future = new \DateTime( self::CURRENT_DATE ); + $future->modify( '+11 days' ); + ClockMock::freeze( $future ); + + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + + $data = $response->get_data()->data; + $station = $data->stations[0]; + + $this->assertEquals( 0, $station->num_vehicles_available ); + } + + public function testStationStatus_withBookingOffset() { + $otherLocationId = $this->createLocation( 'Other Location', ); + $otherItemId = $this->createItem( 'Other Item', ); + + $timeframeID = $this->createTimeframe( + $otherLocationId, + $otherItemId, + strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ), + strtotime( '+10 days', strtotime( self::CURRENT_DATE ) ), + \CommonsBooking\Wordpress\CustomPostType\Timeframe::BOOKABLE_ID, + 'on', + 'd', + 0, + '8:00 AM', + '12:00 PM', + 'publish', + [], + '', + CustomPostTypeTest::USER_ID, + 3, + 30, + 2 + ); + + // with offset → still counted as available because it is not booked + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $data = $response->get_data()->data; + + $relevantStation = current( + array_filter( + $data->stations, + function ( $station ) use ( $otherLocationId ) { + return $station->station_id === (string) $otherLocationId; + } + ) + ); + $this->assertEquals( 1, $relevantStation->num_vehicles_available ); + + // remove offset → still available + update_post_meta( $timeframeID, \CommonsBooking\Model\Timeframe::META_BOOKING_START_DAY_OFFSET, 0 ); + + $response = rest_do_request( $request ); + $data = $response->get_data()->data; + $relevantStation = current( + array_filter( + $data->stations, + function ( $station ) use ( $otherLocationId ) { + return $station->station_id === (string) $otherLocationId; + } + ) + ); + $this->assertEquals( 1, $relevantStation->num_vehicles_available ); + } + public function testStationStatusWithRestriction() { + $this->createRestriction( + Restriction::TYPE_REPAIR, + $this->locationId, + $this->itemId, + strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ), + strtotime( '+1 day', strtotime( self::CURRENT_DATE ) ), + ); + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $data = $response->get_data()->data; + $station = $data->stations[0]; + $this->assertEquals( 0, $station->num_vehicles_available ); + } + + public function testNotCountedWhenItemExcluded() { + update_post_meta( $this->itemId, COMMONSBOOKING_METABOX_PREFIX . 'api_exclude', 'on' ); + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $data = $response->get_data()->data; + $station = $data->stations[0]; + $this->assertEquals( 0, $station->num_vehicles_available ); + } + + public function setUp(): void { + parent::setUp(); + + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + + $this->locationId = $this->createLocation( 'Testlocation', 'publish' ); + $this->itemId = $this->createItem( 'TestItem', 'publish' ); + + $this->createTimeframe( + $this->locationId, + $this->itemId, + strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ), + strtotime( '+10 days', strtotime( self::CURRENT_DATE ) ) + ); + } + + public function tearDown(): void { + ClockMock::reset(); + parent::tearDown(); + } } diff --git a/tests/php/API/GBFS/StationStatusTest.php b/tests/php/API/GBFS/StationStatusTest.php deleted file mode 100644 index 9bac7d5f3..000000000 --- a/tests/php/API/GBFS/StationStatusTest.php +++ /dev/null @@ -1,124 +0,0 @@ -locationId ); - ClockMock::freeze( $currDate ); - $routeObject = new StationStatus(); - $spanningTimeframe = $this->createTimeframe( - $this->locationId, - $this->itemId, - strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ), - strtotime( '+10 days', strtotime( self::CURRENT_DATE ) ) - ); - $stationStatus = $routeObject->prepare_item_for_response( $locationObject, null )->get_data(); - $this->assertEquals( $this->locationId, $stationStatus->station_id ); - $this->assertEquals( 1, $stationStatus->num_vehicles_available ); - $this->assertTrue( $stationStatus->is_installed ); - $this->assertTrue( $stationStatus->is_renting ); - $this->assertTrue( $stationStatus->is_returning ); - $this->assertEquals( date( 'c' ), $stationStatus->last_reported ); - - // now let's book the current day and check, that the station is empty - $this->createConfirmedBookingStartingToday(); - $this->assertEquals( 0, $routeObject->prepare_item_for_response( $locationObject, null )->get_data()->num_vehicles_available ); - - // the timeframe has ended now, so the station should be empty - $currDate->modify( '+11 days' ); - ClockMock::freeze( $currDate ); - $this->assertEquals( 0, $routeObject->prepare_item_for_response( $locationObject, null )->get_data()->num_vehicles_available ); - - // very important for GBFS: when bookings are only allowed with a certain offset (time difference between booking and start of booking), the station should be empty - ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); - $otherLocationId = $this->createLocation( 'Other Location', 'publish' ); - $otherItemId = $this->createItem( 'Other Item', 'publish' ); - $timeframeID = $this->createTimeframe( - $otherLocationId, - $otherItemId, - strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ), - strtotime( '+10 days', strtotime( self::CURRENT_DATE ) ), - \CommonsBooking\Wordpress\CustomPostType\Timeframe::BOOKABLE_ID, - 'on', - 'd', - 0, - '8:00 AM', - '12:00 PM', - 'publish', - [], - '', - self::USER_ID, - 3, - 30, - 2 - ); - $this->assertEquals( 0, $routeObject->prepare_item_for_response( new Location( $otherLocationId ), null )->get_data()->num_vehicles_available ); - // remove the offset and the station should have the item - update_post_meta( $timeframeID, 'booking-startday-offset', 0 ); - $this->assertEquals( 1, $routeObject->prepare_item_for_response( new Location( $otherLocationId ), null )->get_data()->num_vehicles_available ); - } - - public function testPrepare_item_for_response_hourly() { - $currDate = new \DateTime( self::CURRENT_DATE ); - $currDate->setTime( 8, 0, 0 ); - $locationObject = new Location( $this->locationId ); - ClockMock::freeze( $currDate ); - $routeObject = new StationStatus(); - $hourlyTimeframe = $this->createTimeframe( - $this->locationId, - $this->itemId, - strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ), - strtotime( '+2 days', strtotime( self::CURRENT_DATE ) ), - \CommonsBooking\Wordpress\CustomPostType\Timeframe::BOOKABLE_ID, - 'off', - 'd', - 1, - '8:00 AM', - '11:59 PM' - ); - $this->assertEquals( 1, $routeObject->prepare_item_for_response( $locationObject, null )->get_data()->num_vehicles_available ); - - // before 08:00AM the bike is not available - $currDate->setTime( 6, 0, 0 ); - ClockMock::freeze( $currDate ); - $this->assertEquals( 0, $routeObject->prepare_item_for_response( $locationObject, null )->get_data()->num_vehicles_available ); - - // now let's book two hours out of the timeframe and check that the station is empty for those two hours - $startBooking = new \DateTime( self::CURRENT_DATE ); - $startBooking->setTime( 10, 0, 0 ); - $endBooking = clone $startBooking; - $endBooking->setTime( 13, 0, 0 ); - $this->createBooking( - $this->locationId, - $this->itemId, - strtotime( '10:00 AM', strtotime( self::CURRENT_DATE ) ), - strtotime( '01:00 PM', strtotime( self::CURRENT_DATE ) ), - '10:00 AM', - '01:00 PM' - ); - ClockMock::freeze( $startBooking ); - $this->assertEquals( 0, $routeObject->prepare_item_for_response( $locationObject, null )->get_data()->num_vehicles_available ); - $startBooking->modify( '+1 hour' ); - ClockMock::freeze( $startBooking ); - $this->assertEquals( 0, $routeObject->prepare_item_for_response( $locationObject, null )->get_data()->num_vehicles_available ); - ClockMock::freeze( $endBooking ); - $this->assertEquals( 1, $routeObject->prepare_item_for_response( $locationObject, null )->get_data()->num_vehicles_available ); - } - - protected function setUp(): void { - parent::setUp(); - } - - protected function tearDown(): void { - parent::tearDown(); - } -} diff --git a/tests/php/API/GBFS/SystemInformationRouteTest.php b/tests/php/API/GBFS/SystemInformationRouteTest.php index 0dc4b8b26..bd8c4fb12 100644 --- a/tests/php/API/GBFS/SystemInformationRouteTest.php +++ b/tests/php/API/GBFS/SystemInformationRouteTest.php @@ -3,11 +3,54 @@ namespace CommonsBooking\Tests\API\GBFS; use CommonsBooking\Tests\API\CB_REST_Route_UnitTestCase; +use SlopeIt\ClockMock\ClockMock; -/** - * TODO: add result unit test - */ class SystemInformationRouteTest extends CB_REST_Route_UnitTestCase { protected $ENDPOINT = '/commonsbooking/v1/system_information.json'; + + public function testRoute() { + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + + $data = $response->get_data()->data; + $this->assertNotEmpty( $data->name ); + $this->assertNotEmpty( $data->system_id ); + + $header = $response->get_data(); // the top level info that is always present + + $this->assertNotFalse( \DateTime::createFromFormat( \DateTime::ATOM, $header->last_updated ) ); + $this->assertIsInt( $header->ttl ); + $this->assertIsString( $header->version ); + parent::testRoute(); + } + + public function testOpeningHours() { + // no timeframe setup, meaning no items to book -> closed + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $data = $response->get_data()->data; + $this->assertEquals( '24/7 closed', $data->opening_hours ); + + // with timeframe, is open + $this->createBookableTimeFrameIncludingCurrentDay(); + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $data = $response->get_data()->data; + $this->assertEquals( '24/7', $data->opening_hours ); + + // outside of the timeframe, closed again + $inAWeek = new \DateTime( self::CURRENT_DATE ); + $inAWeek->modify( '+1 week' ); + ClockMock::freeze( $inAWeek ); + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $data = $response->get_data()->data; + $this->assertEquals( '24/7 closed', $data->opening_hours ); + } + + public function setUp(): void { + parent::setUp(); + } } diff --git a/tests/php/API/GBFS/VehicleAvailabilityRouteTest.php b/tests/php/API/GBFS/VehicleAvailabilityRouteTest.php new file mode 100644 index 000000000..7f8bd7a05 --- /dev/null +++ b/tests/php/API/GBFS/VehicleAvailabilityRouteTest.php @@ -0,0 +1,173 @@ +ENDPOINT ); + $response = rest_do_request( $request ); + + $this->assertSame( 200, $response->get_status() ); + + $data = $response->get_data()->data; + $this->assertNotEmpty( $data->vehicles ); + $this->assertCount( 1, $data->vehicles ); + $availabilities = $data->vehicles[0]->availabilities; + $this->assertCount( 1, $availabilities ); + + $startDT = new \DateTime( $availabilities[0]->from ); + $today = new \DateTime( self::CURRENT_DATE ); + + $this->assertEqualsWithDelta( $today->getTimestamp(), $startDT->getTimestamp(), 1.0 ); + } + + public function testAvailabilityWithOffset() { + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + + // delete other timeframe so it doesn't mess with our tests + wp_delete_post( $this->timeframe, true ); + $otherLocationId = $this->createLocation( 'Other Location', ); + $otherItemId = $this->createItem( 'Other Item', ); + + $timeframeID = $this->createTimeframe( + $otherLocationId, + $otherItemId, + strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ), + strtotime( '+10 days', strtotime( self::CURRENT_DATE ) ), + \CommonsBooking\Wordpress\CustomPostType\Timeframe::BOOKABLE_ID, + 'on', + 'd', + 0, + '8:00 AM', + '12:00 PM', + 'publish', + [], + '', + CustomPostTypeTest::USER_ID, + 3, + 30, + 2 + ); + + // with offset → not available right now + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $data = $response->get_data()->data; + + $availabilities = $data->vehicles[0]->availabilities; + + $startDT = new \DateTime( $availabilities[0]->from ); + $today = new \DateTime( self::CURRENT_DATE ); + + $this->assertNotEqualsWithDelta( $today->getTimestamp(), $startDT->getTimestamp(), 1.0 ); + + // remove offset → now available today + update_post_meta( $timeframeID, \CommonsBooking\Model\Timeframe::META_BOOKING_START_DAY_OFFSET, 0 ); + + $response = rest_do_request( $request ); + $data = $response->get_data()->data; + $availabilities = $data->vehicles[0]->availabilities; + $this->assertCount( 1, $availabilities ); + + $startDT = new \DateTime( $availabilities[0]->from ); + $today = new \DateTime( self::CURRENT_DATE ); + + $this->assertEqualsWithDelta( $today->getTimestamp(), $startDT->getTimestamp(), 1.0 ); + } + + public function testHourlyAvailability() { + delete_post_meta( $this->timeframe, 'full-day', 'on' ); + update_post_meta( $this->timeframe, 'grid', 1 ); // hourly grid + update_post_meta( $this->timeframe, 'start-time', '08:00 AM' ); + update_post_meta( $this->timeframe, 'end-time', '01:00 PM' ); + + $startDT = new \DateTime(); + $startDT->modify( '08:00 AM' ); + $endDT = new \DateTime(); + $endDT->modify( '01:00 PM' ); + $endDT->modify( '-1 second' ); // timeframes always have one second cut + + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $this->assertSame( 200, $response->get_status() ); + + $data = $response->get_data()->data; + $this->assertNotEmpty( $data->vehicles ); + $this->assertCount( 1, $data->vehicles ); + $availabilities = $data->vehicles[0]->availabilities; + $this->assertCount( 2, $availabilities ); // today and tomorrow + $this->assertEquals( $startDT->format( 'c' ), $availabilities[0]->from ); + $this->assertEquals( $endDT->format( 'c' ), $availabilities[0]->until ); + } + + public function testVehicleIDChanges() { + // test, that the vehicle ID rotates after each trip + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $this->assertSame( 200, $response->get_status() ); + + $data = $response->get_data()->data; + $id = $data->vehicles[0]->vehicle_id; + + // add a trip in the past + $this->createBooking( + $this->locationId, + $this->itemId, + strtotime( '-2 days', strtotime( self::CURRENT_DATE ) ), + strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ) + ); + + // after the trip, the vehicle ID should have changed + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $this->assertSame( 200, $response->get_status() ); + $data = $response->get_data()->data; + + $this->assertNotEquals( $id, $data->vehicles[0]->vehicle_id ); + } + + public function testExcludedIfBoxChecked() { + update_post_meta( $this->itemId, COMMONSBOOKING_METABOX_PREFIX . 'api_exclude', 'on' ); + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $this->assertSame( 200, $response->get_status() ); + $data = $response->get_data()->data; + $this->assertEmpty( $data->vehicles ); + } + + public function setUp(): void { + parent::setUp(); + + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + + $this->locationId = $this->createLocation( 'Testlocation', 'publish', [] ); + $this->itemId = $this->createItem( 'TestItem', 'publish' ); + + $mocked = new \DateTimeImmutable( self::CURRENT_DATE ); + $this->start = $mocked->modify( '-1 days' ); + $this->end = $mocked->modify( '+1 days' ); + + $this->timeframe = $this->createTimeframe( + $this->locationId, + $this->itemId, + $this->start->getTimestamp(), + $this->end->getTimestamp() + ); + } + + public function tearDown(): void { + ClockMock::reset(); + parent::tearDown(); + } +} diff --git a/tests/php/API/GBFS/VehicleStatusRouteTest.php b/tests/php/API/GBFS/VehicleStatusRouteTest.php new file mode 100644 index 000000000..7918b06a5 --- /dev/null +++ b/tests/php/API/GBFS/VehicleStatusRouteTest.php @@ -0,0 +1,326 @@ +ENDPOINT ); + $response = rest_do_request( $request ); + + $this->assertSame( 200, $response->get_status() ); + + $data = $response->get_data()->data; + + $this->assertCount( 1, $data->vehicles ); + + $this->createConfirmedBookingStartingToday(); + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $this->assertSame( 200, $response->get_status() ); + $data = $response->get_data()->data; + $this->assertEmpty( $data->vehicles ); + } + + /** + * Item should not appear, when it is currently not available for rent. + * + * @return void + */ + public function testNoTimeframe() { + // base case, not disabled + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $this->assertSame( 200, $response->get_status() ); + $data = $response->get_data()->data; + $this->assertFalse( $data->vehicles[0]->is_disabled ); + + // timeframe expired: item vanishes from feed + $future = $this->end->modify( '+1 day' ); + ClockMock::freeze( $future ); + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $this->assertSame( 200, $response->get_status() ); + $data = $response->get_data()->data; + $this->assertEmpty( $data->vehicles ); + } + + /** + * This field is used to indicate vehicles that are in the field but not available for rental due to a mechanical issue or low battery etc. + * Publishing this data may prevent users from attempting to rent vehicles that are disabled and not available for rental. + * This field SHOULD NOT be set to true when the system is closed for vehicles that would otherwise be rentable. + * + * In CB, this is handled through restrictions. When a total breakdown is present, the item is disabled. + * @return void + */ + public function testIsDisabled() { + // base case, not disabled + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $this->assertSame( 200, $response->get_status() ); + $data = $response->get_data()->data; + $this->assertFalse( $data->vehicles[0]->is_disabled ); + + // restriction present: should not disappear from feed, but is considered disabled + $this->createRestriction( + \CommonsBooking\Model\Restriction::TYPE_REPAIR, + $this->locationId, + $this->itemId, + strtotime( self::CURRENT_DATE ), + strtotime( '+1 day', strtotime( self::CURRENT_DATE ) ) + ); + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $this->assertSame( 200, $response->get_status() ); + $data = $response->get_data()->data; + $this->assertCount( 1, $data->vehicles ); + $this->assertTrue( $data->vehicles[0]->is_disabled ); + } + + public function testIsDisabled_hint() { + // hints should not affect availability + $this->createRestriction( + \CommonsBooking\Model\Restriction::TYPE_HINT, + $this->locationId, + $this->itemId, + strtotime( self::CURRENT_DATE ), + strtotime( '+2 days', strtotime( self::CURRENT_DATE ) ) + ); + + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $this->assertSame( 200, $response->get_status() ); + $data = $response->get_data()->data; + $this->assertFalse( $data->vehicles[0]->is_disabled ); + } + + public function testIsDisabled_inFuture() { + // restrictions in the future should not affect current state + $this->createRestriction( + \CommonsBooking\Model\Restriction::TYPE_REPAIR, + $this->locationId, + $this->itemId, + strtotime( '+1 day', strtotime( self::CURRENT_DATE ) ), + strtotime( '+2 days', strtotime( self::CURRENT_DATE ) ) + ); + + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $this->assertSame( 200, $response->get_status() ); + $data = $response->get_data()->data; + $this->assertFalse( $data->vehicles[0]->is_disabled ); + } + + public function testIsDisabled_inactiveRestriction() { + // inactive restrictions should also not trigger + $this->createRestriction( + \CommonsBooking\Model\Restriction::TYPE_REPAIR, + $this->locationId, + $this->itemId, + strtotime( self::CURRENT_DATE ), + null, + \CommonsBooking\Model\Restriction::STATE_SOLVED + ); + + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $this->assertSame( 200, $response->get_status() ); + $data = $response->get_data()->data; + $this->assertFalse( $data->vehicles[0]->is_disabled ); + } + + public function testExclusion() { + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + update_post_meta( $this->itemId, COMMONSBOOKING_METABOX_PREFIX . 'api_exclude', 'on' ); + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $this->assertSame( 200, $response->get_status() ); + $data = $response->get_data()->data; + $this->assertEmpty( $data->vehicles ); + } + + public function testAvailableUntil_BaseCase() { + $rightNow = new \DateTime( self::CURRENT_DATE ); + ClockMock::freeze( $rightNow ); + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $this->assertSame( 200, $response->get_status() ); + $data = $response->get_data()->data; + $inThreeDays = clone $rightNow; + $inThreeDays->modify( '+3 days' ); + $inThreeDays->modify( '-1 second' ); // because the item is only available exactly three days, not on the fourth + + $this->assertCount( 1, $data->vehicles ); + $this->assertSame( $inThreeDays->format( 'c' ), $data->vehicles[0]->available_until ); + } + + public function testAvailableUntil_hourlyBooking() { + // delete our original timeframe so we don't have multiple vehicles + wp_delete_post( $this->timeframe, true ); + + // create a timeframe with hourly availability and one day max booking + $this->createTimeframe( + $this->locationId, + $this->itemId, + strtotime( self::CURRENT_DATE ), + null, + Timeframe::BOOKABLE_ID, + 'off', + 'd', + 1, + '8:00 AM', + '5:00 PM', + 'publish', + [ '1', '2', '3', '4', '5', '6', '7' ], + '', + CustomPostTypeTest::USER_ID, + 1 + ); + + $rightNow = new \DateTime( self::CURRENT_DATE . ' 10:00 AM' ); + ClockMock::freeze( $rightNow ); + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $this->assertSame( 200, $response->get_status() ); + $data = $response->get_data()->data; + $sameDayFivePM = clone $rightNow; + $sameDayFivePM->modify( '5:00 PM' ); + $sameDayFivePM->modify( '-1 second' ); + + $this->assertCount( 1, $data->vehicles ); + $this->assertSame( $sameDayFivePM->format( 'c' ), $data->vehicles[0]->available_until ); + } + + public function testAvailableUntil_slotBased() { + // delete our original timeframe so we don't have multiple vehicles + wp_delete_post( $this->timeframe, true ); + + // create a timeframe a slot based timeframe and one day max booking + $this->createTimeframe( + $this->locationId, + $this->itemId, + strtotime( self::CURRENT_DATE ), + null, + Timeframe::BOOKABLE_ID, + 'off', + 'd', + 0, + '8:00 AM', + '10:00 AM', + 'publish', + [ '1', '2', '3', '4', '5', '6', '7' ], + '', + CustomPostTypeTest::USER_ID, + 1 + ); + + // create another slot for the afternoon + $this->createTimeframe( + $this->locationId, + $this->itemId, + strtotime( self::CURRENT_DATE ), + null, + Timeframe::BOOKABLE_ID, + 'off', + 'd', + 0, + '1:00 PM', + '5:00 PM', + 'publish', + [ '1', '2', '3', '4', '5', '6', '7' ], + '', + CustomPostTypeTest::USER_ID, + 1 + ); + + $rightNow = new \DateTime( self::CURRENT_DATE . ' 9:00 AM' ); + ClockMock::freeze( $rightNow ); + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $this->assertSame( 200, $response->get_status() ); + $data = $response->get_data()->data; + $sameDayFivePM = clone $rightNow; + $sameDayFivePM->modify( '5:00 PM' ); + $sameDayFivePM->modify( '-1 second' ); + + $this->assertCount( 1, $data->vehicles ); + $this->assertSame( $sameDayFivePM->format( 'c' ), $data->vehicles[0]->available_until ); + } + + public function testAvailableUntil_offset() { + // delete our original timeframe so we don't have multiple vehicles + wp_delete_post( $this->timeframe, true ); + + $rightNow = new \DateTime( self::CURRENT_DATE ); + ClockMock::freeze( $rightNow ); + $otherLocationId = $this->createLocation( 'Other Location', ); + $otherItemId = $this->createItem( 'Other Item', ); + + $timeframeID = $this->createTimeframe( + $otherLocationId, + $otherItemId, + strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ), + strtotime( '+10 days', strtotime( self::CURRENT_DATE ) ), + \CommonsBooking\Wordpress\CustomPostType\Timeframe::BOOKABLE_ID, + 'on', + 'd', + 0, + '8:00 AM', + '12:00 PM', + 'publish', + [], + '', + CustomPostTypeTest::USER_ID, + 3, + 30, + 2 + ); + + // with offset - available until is extended to account for the offset + $availableUntil = clone $rightNow; + $availableUntil->modify( '+5 days' ); + $availableUntil->modify( '-1 second' ); + + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $data = $response->get_data()->data; + + $this->assertCount( 1, $data->vehicles ); + $this->assertSame( $availableUntil->format( 'c' ), $data->vehicles[0]->available_until ); + } + + public function setUp(): void { + parent::setUp(); + + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + + $this->locationId = $this->createLocation( 'Testlocation', 'publish', [] ); + $this->itemId = $this->createItem( 'TestItem', 'publish' ); + + $mocked = new \DateTimeImmutable( self::CURRENT_DATE ); + $this->start = $mocked->modify( '-1 days' ); + $this->end = $mocked->modify( '+5 days' ); + + $this->timeframe = $this->createTimeframe( + $this->locationId, + $this->itemId, + $this->start->getTimestamp(), + $this->end->getTimestamp() + ); + } + + public function tearDown(): void { + ClockMock::reset(); + parent::tearDown(); + } +} diff --git a/tests/php/API/GBFS/VehicleTypesRouteTest.php b/tests/php/API/GBFS/VehicleTypesRouteTest.php new file mode 100644 index 000000000..dfbb6e0ab --- /dev/null +++ b/tests/php/API/GBFS/VehicleTypesRouteTest.php @@ -0,0 +1,22 @@ +ENDPOINT ); + $response = rest_do_request( $request ); + + $this->assertSame( 200, $response->get_status() ); + + $data = $response->get_data()->data; + + $this->assertCount( 1, $data->vehicle_types ); // just one vehicle type with the default settings + + parent::testRoute(); + } +} diff --git a/tests/php/API/ItemsRouteTest.php b/tests/php/API/ItemsRouteTest.php index 52f9f7b3e..1287a3d18 100644 --- a/tests/php/API/ItemsRouteTest.php +++ b/tests/php/API/ItemsRouteTest.php @@ -81,4 +81,31 @@ public function testSingleItem() { $this->assertCount( 1, $data->items ); $this->assertEquals( (string) $this->itemId, $data->items[0]->id ); } + + public function testTitleHtmlEntitiesAreDecoded() { + $entityItemId = $this->createItem( 'Bohrmaschine & Akkuschrauber 'Pro'', 'publish' ); + + // Sanity check: WordPress stores the title with the encoded entity. + $this->assertStringContainsString( '&', get_post( $entityItemId )->post_title ); + + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT . '/' . $entityItemId ); + $response = rest_do_request( $request ); + + $this->assertSame( 200, $response->get_status() ); + + $item = $response->get_data()->items[0]; + $this->assertEquals( 'Bohrmaschine & Akkuschrauber \'Pro\'', $item->name ); + } + + public function testExcludedIfBoxChecked() { + update_post_meta( $this->itemId, COMMONSBOOKING_METABOX_PREFIX . 'api_exclude', 'on' ); + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT . '/' . $this->itemId ); + $response = rest_do_request( $request ); + + $this->assertSame( 200, $response->get_status() ); + + $data = $response->get_data(); + + $this->assertEmpty( $data->items ); + } } diff --git a/tests/php/API/LocationsRouteTest.php b/tests/php/API/LocationsRouteTest.php index e0d53a7e1..6b3e83c45 100644 --- a/tests/php/API/LocationsRouteTest.php +++ b/tests/php/API/LocationsRouteTest.php @@ -58,6 +58,21 @@ public function testMultipleLocations() { $this->assertContains( (string) $secondId, $ids ); } + public function testTitleHtmlEntitiesAreDecoded() { + $entityLocationId = $this->createLocation( 'Markt & Mehr', 'publish', [] ); + + // Sanity check: WordPress stores the title with the encoded entity. + $this->assertStringContainsString( '&', get_post( $entityLocationId )->post_title ); + + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT . '/' . $entityLocationId ); + $response = rest_do_request( $request ); + + $this->assertSame( 200, $response->get_status() ); + + $feature = $response->get_data()->locations->features[0]; + $this->assertEquals( 'Markt & Mehr', $feature->properties->name ); + } + public function testEmptyLocations() { // Remove the location created in setUp wp_delete_post( array_pop( $this->locationIds ), true ); diff --git a/tests/php/Model/CalendarTest.php b/tests/php/Model/CalendarTest.php index 65481071b..ae414af6a 100644 --- a/tests/php/Model/CalendarTest.php +++ b/tests/php/Model/CalendarTest.php @@ -92,6 +92,22 @@ public function testGetAvailabilitySlots() { ], ]; $this->assertEquals( $expectedSlotObject, $availabilitySlots ); + + // book the other day too, assert an empty + $this->createBooking( + $this->locationId, + $this->itemId, + strtotime( $tomorrow ), + $tomorrowEnd + ); + // recreate the calendar object to get the updated availability + $this->calendar = new Calendar( + new Day( $today, [ $this->locationId ], [ $this->itemId ] ), + new Day( $tomorrow, [ $this->locationId ], [ $this->itemId ] ), + [ $this->locationId ], + [ $this->itemId ] + ); + $this->assertEmpty( $this->calendar->getAvailabilitySlots() ); } public function testGetAvailabilitySlotsWithHourlyTimeframe() { diff --git a/tests/php/Model/ItemTest.php b/tests/php/Model/ItemTest.php index abfa1c997..e564cd5bd 100644 --- a/tests/php/Model/ItemTest.php +++ b/tests/php/Model/ItemTest.php @@ -6,6 +6,7 @@ use CommonsBooking\Model\Restriction; use CommonsBooking\Model\Timeframe; use CommonsBooking\Tests\Wordpress\CustomPostTypeTest; +use SlopeIt\ClockMock\ClockMock; class ItemTest extends CustomPostTypeTest { @@ -55,6 +56,280 @@ public function testGetRestrictions() { } */ + public function testGetLocation() { + $dt = new \DateTime( self::CURRENT_DATE ); + ClockMock::freeze( $dt ); + + // just one item that is currently bookable + $this->assertEquals( $this->locationId, $this->itemModel->getLocation()->ID ); + + // in two weeks, the timeframe is expired, so the item will not be at the location anymore + $dt->modify( '+2 weeks' ); + ClockMock::freeze( $dt ); + $this->assertNull( $this->itemModel->getLocation() ); + + // item that is in location A monday-thursday and in location B friday-sunday. Position should change depending on the day of the week + $locationA = $this->createLocation( 'location a' ); + $locationB = $this->createLocation( 'location b' ); + $movingItem = $this->createItem( 'location changing item' ); + $movingItemModel = new Item( $movingItem ); + $tf1 = new Timeframe( + $this->createTimeframe( + $locationA, + $movingItem, + strtotime( '-1 day', strtotime( \CommonsBooking\Tests\Wordpress\CustomPostTypeTest::CURRENT_DATE ) ), + strtotime( '+14 days', strtotime( \CommonsBooking\Tests\Wordpress\CustomPostTypeTest::CURRENT_DATE ) ), + \CommonsBooking\Wordpress\CustomPostType\Timeframe::BOOKABLE_ID, + '', + 'w', + 0, + '8:00 AM', + '12:00 PM', + 'publish', + [ '1','2','3','4' ] + ) + ); + $tf2 = new Timeframe( + $this->createTimeframe( + $locationB, + $movingItem, + strtotime( '-1 day', strtotime( \CommonsBooking\Tests\Wordpress\CustomPostTypeTest::CURRENT_DATE ) ), + strtotime( '+14 days', strtotime( \CommonsBooking\Tests\Wordpress\CustomPostTypeTest::CURRENT_DATE ) ), + \CommonsBooking\Wordpress\CustomPostType\Timeframe::BOOKABLE_ID, + '', + 'w', + 0, + '8:00 AM', + '12:00 PM', + 'publish', + [ '5','6','7' ] + ) + ); + $this->assertFalse( $tf1->overlaps( $tf2 ) ); + $dt = new \DateTime( self::CURRENT_DATE ); + $dt->modify( 'monday' ); + ClockMock::freeze( $dt ); + $this->assertEquals( $locationA, $movingItemModel->getLocation()->ID ); + $dt->modify( 'friday' ); + ClockMock::freeze( $dt ); + $this->assertEquals( $locationB, $movingItemModel->getLocation()->ID ); + } + + public function testGetCloakedID() { + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + $cloakedID = $this->itemModel->getCloakedId(); + $this->assertIsString( $cloakedID ); + // create a booking, assert that it has changed + $this->createBooking( + $this->locationId, + $this->itemId, + strtotime( '-2 days', strtotime( self::CURRENT_DATE ) ), + strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ) + ); + $cloakedIDWithBooking = $this->itemModel->getCloakedId(); + $this->assertNotEquals( $cloakedID, $cloakedIDWithBooking ); + + // this booking is not in the past, trip has not ended. Therefore it should not affect the ID + $booking = $this->createConfirmedBookingStartingToday(); + $cloakedIDwithTwoBookings = $this->itemModel->getCloakedId(); + $this->assertEquals( $cloakedIDWithBooking, $cloakedIDwithTwoBookings ); + } + + public function testGetClosestBooking() { + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + // no booking present + $this->assertNull( $this->itemModel->getClosestBooking() ); + + // one past booking + $bookingInPast = $this->createBooking( + $this->locationId, + $this->itemId, + strtotime( '-4 days', strtotime( self::CURRENT_DATE ) ), + strtotime( '-3 days', strtotime( self::CURRENT_DATE ) ) + ); + $closestBooking = $this->itemModel->getClosestBooking(); + $this->assertEquals( $bookingInPast, $closestBooking->ID ); + + // newer booking in front of that + $newerBooking = $this->createBooking( + $this->locationId, + $this->itemId, + strtotime( '-2 days', strtotime( self::CURRENT_DATE ) ), + strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ) + ); + $closestBooking = $this->itemModel->getClosestBooking(); + $this->assertEquals( $newerBooking, $closestBooking->ID ); + + // booking in future (should not affect) + $this->createBooking( + $this->locationId, + $this->itemId, + strtotime( '+3 days' ), + strtotime( '+4 days' ) + ); + $this->assertEquals( $newerBooking, $this->itemModel->getClosestBooking()->ID ); + } + + // Test case where last booking is way in the past but other booking is in the nearer future. Should still return booking in the past + public function testGetClosestBooking_notIncludingFutureBookings() { + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + // one past booking + $pastBooking = $this->createBooking( + $this->locationId, + $this->itemId, + strtotime( '-7 days' ), + strtotime( '-5 days' ) + ); + // one future booking + $bookingStartingTomorrow = $this->createBooking( + $this->locationId, + $this->itemId, + strtotime( '+1 day' ), + strtotime( '+2 days' ) + ); + $closestBooking = $this->itemModel->getClosestBooking(); + $this->assertEquals( $pastBooking, $closestBooking->ID ); + } + + public function testGetClosestBooking_picksMostRecentPastBooking() { + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + $this->createBooking( + $this->locationId, + $this->itemId, + strtotime( '-14 days' ), + strtotime( '-12 days' ) + ); + $recentPastBooking = $this->createBooking( + $this->locationId, + $this->itemId, + strtotime( '-3 days' ), + strtotime( '-1 day' ) + ); + $this->createBooking( + $this->locationId, + $this->itemId, + strtotime( '+1 day' ), + strtotime( '+2 days' ) + ); + + $closestBooking = $this->itemModel->getClosestBooking(); + $this->assertEquals( $recentPastBooking, $closestBooking->ID ); + } + + public function testIsCurrentlyFreeAtLocation() { + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + + // Item has a bookable timeframe including today, should be free + $this->assertTrue( $this->itemModel->isCurrentlyFreeAtLocation( $this->locationId ) ); + + // A confirmed booking starting today means the item is now rented + $this->createConfirmedBookingStartingToday(); + $this->assertFalse( $this->itemModel->isCurrentlyFreeAtLocation( $this->locationId ) ); + + // In two weeks, the timeframe is expired, should no longer be free + $dt = new \DateTime( self::CURRENT_DATE ); + $dt->modify( '+2 weeks' ); + ClockMock::freeze( $dt ); + $this->assertFalse( $this->itemModel->isCurrentlyFreeAtLocation( $this->locationId ) ); + + // Wrong location should not be free + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + $otherLocationId = $this->createLocation( 'other location' ); + $this->assertFalse( $this->itemModel->isCurrentlyFreeAtLocation( $otherLocationId ) ); + } + + public function testIsCurrentlyFreeAtLocation_withBookingOffset() { + $otherLocationId = $this->createLocation( 'Other Location' ); + $otherItemId = $this->createItem( 'Other Item' ); + $otherItemModel = new Item( $otherItemId ); + + $timeframeId = $this->createTimeframe( + $otherLocationId, + $otherItemId, + strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ), + strtotime( '+10 days', strtotime( self::CURRENT_DATE ) ), + \CommonsBooking\Wordpress\CustomPostType\Timeframe::BOOKABLE_ID, + 'on', + 'd', + 0, + '8:00 AM', + '12:00 PM', + 'publish', + [], + '', + CustomPostTypeTest::USER_ID, + 3, // booking start day offset + 30, + 2 + ); + + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + + // With offset → item is still free, it's just not possible to pick it up right now + $this->assertTrue( $otherItemModel->isCurrentlyFreeAtLocation( $otherLocationId, true ) ); + + // Remove offset → still free, no change in rental status + update_post_meta( $timeframeId, \CommonsBooking\Model\Timeframe::META_BOOKING_START_DAY_OFFSET, 0 ); + $this->assertTrue( $otherItemModel->isCurrentlyFreeAtLocation( $otherLocationId, true ) ); + } + + public function testGetClosestBookableTimeframe() { + $dt = new \DateTime( self::CURRENT_DATE ); + ClockMock::freeze( $dt ); + $this->assertEquals( $this->timeframeModel->ID, $this->itemModel->getClosestBookableTimeframe()->ID ); + // in two weeks, the timeframe is expired, so the item will not be at the location anymore + $dt->modify( '+2 weeks' ); + ClockMock::freeze( $dt ); + $this->assertNull( $this->itemModel->getClosestBookableTimeframe() ); + } + + public function testGetClosestBookableTimeframe_withBookingOffset() { + $otherLocationId = $this->createLocation( 'Other Location' ); + $otherItemId = $this->createItem( 'Other Item' ); + $otherItemModel = new Item( $otherItemId ); + + $timeframeId = $this->createTimeframe( + $otherLocationId, + $otherItemId, + strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ), + strtotime( '+10 days', strtotime( self::CURRENT_DATE ) ), + \CommonsBooking\Wordpress\CustomPostType\Timeframe::BOOKABLE_ID, + 'on', + 'd', + 0, + '8:00 AM', + '12:00 PM', + 'publish', + [], + '', + CustomPostTypeTest::USER_ID, + 3, // booking start day offset + 30, + 2 + ); + + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + + // should still show the timeframe as the closest + $this->assertEquals( $timeframeId, $otherItemModel->getClosestBookableTimeframe()->ID ); + } + + public function testGetClosestBookableTimeframe_withSlots() { + $otherLocationId = $this->createLocation( 'Other Location' ); + $otherItemId = $this->createItem( 'Other Item' ); + $timeframes = $this->createTwoBookableTimeframeSlotsIncludingCurrentDay( $otherLocationId, $otherItemId ); + $otherItemModel = new Item( $otherItemId ); + $dt = new \DateTime( self::CURRENT_DATE ); + ClockMock::freeze( $dt ); + + // even though it is not open yet (bc we have midnight), the first slot should be the closest + $this->assertEquals( $timeframes[0], $otherItemModel->getClosestBookableTimeframe()->ID ); + + // After 3PM, the other one should be picked + $dt->modify( '15:01' ); + ClockMock::freeze( $dt ); + $this->assertEquals( $timeframes[1], $otherItemModel->getClosestBookableTimeframe()->ID ); + } protected function setUp(): void { parent::setUp(); $this->restrictionIds[] = $this->createRestriction( diff --git a/tests/php/PluginTest.php b/tests/php/PluginTest.php index ce7bfd027..9587fed77 100644 --- a/tests/php/PluginTest.php +++ b/tests/php/PluginTest.php @@ -6,11 +6,88 @@ use CommonsBooking\Plugin; use CommonsBooking\Tests\Wordpress\CustomPostTypeTest; use CommonsBooking\Wordpress\CustomPostType\CustomPostType; +use CommonsBooking\Wordpress\CustomPostType\Item; +use CommonsBooking\Wordpress\CustomPostType\Location; class PluginTest extends CustomPostTypeTest { private $postIDs = []; + + /** + * Regression test for wielebenwir/commonsbooking#1510. + * + * The item/location category submenu pages linked to + * edit-tags.php?taxonomy= without passing the post_type. Because of + * that, the "Anzahl" (count) column on the category overview built its link + * with the default `post` post type, so clicking it listed no items at all. + * + * The category menu URLs must carry the matching post_type so the overview + * (and the count link WordPress derives from the screen) target the correct + * custom post type. + * + * @return void + */ + public function testCategoryMenuPagesPassPostType() { + // The category submenus are only registered for admins. + $this->createAdministrator(); + wp_set_current_user( $this->adminUserID ); + + require_once ABSPATH . 'wp-admin/includes/plugin.php'; + + // Start from a clean menu state so we only inspect what addMenuPages() registers. + global $menu, $submenu; + $menu = []; + $submenu = []; + + Plugin::addMenuPages(); + + $this->assertArrayHasKey( + 'cb-dashboard', + $submenu, + 'Expected commonsbooking submenu pages to be registered under cb-dashboard.' + ); + + $cases = [ + Item::getTaxonomyName() => Item::getPostType(), + Location::getTaxonomyName() => Location::getPostType(), + ]; + + foreach ( $cases as $taxonomy => $postType ) { + $menuSlug = null; + foreach ( $submenu['cb-dashboard'] as $entry ) { + // Index 2 holds the menu slug / URL of the submenu page. + if ( isset( $entry[2] ) && strpos( $entry[2], 'taxonomy=' . $taxonomy ) !== false ) { + $menuSlug = $entry[2]; + break; + } + } + + $this->assertNotNull( + $menuSlug, + sprintf( 'Category menu page for taxonomy "%s" was not registered.', $taxonomy ) + ); + + // Parse the query string to compare the actual param value. + $query = wp_parse_url( $menuSlug, PHP_URL_QUERY ); + parse_str( (string) $query, $params ); + + $this->assertArrayHasKey( + 'post_type', + $params, + sprintf( + 'Category menu URL for taxonomy "%s" is missing the post_type param (#1510): %s', + $taxonomy, + $menuSlug + ) + ); + $this->assertSame( + $postType, + $params['post_type'], + sprintf( 'Category menu URL for taxonomy "%s" points at the wrong post_type.', $taxonomy ) + ); + } + } public function testGetCustomPostTypes() { $this->assertIsArray( Plugin::getCustomPostTypes() ); // make sure, that we also have a model for each custom post type diff --git a/tests/php/Repository/ItemTest.php b/tests/php/Repository/ItemTest.php index 64baef6f6..d559fbe95 100644 --- a/tests/php/Repository/ItemTest.php +++ b/tests/php/Repository/ItemTest.php @@ -4,21 +4,44 @@ use CommonsBooking\Repository\Item; use CommonsBooking\Tests\Wordpress\CustomPostTypeTest; +use SlopeIt\ClockMock\ClockMock; class ItemTest extends CustomPostTypeTest { protected function setUp(): void { parent::setUp(); - - // Create timeframe with location and item, so that we can search vor it + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + // Create timeframe with location and item, so that we can search for it $this->createTimeframe( $this->locationId, $this->itemId, - strtotime( 'midnight' ), - strtotime( '+90 days' ) + strtotime( 'midnight', strtotime( self::CURRENT_DATE ) ), + strtotime( '+90 days', strtotime( self::CURRENT_DATE ) ) ); } + public function testGetByCloakedId(): void { + $itemModel = new \CommonsBooking\Model\Item( $this->itemId ); + + // basic test, without any booking + $cloakedId = $itemModel->getCloakedId(); + $this->assertEquals( $this->itemId, Item::getByCloakedId( $cloakedId )->ID ); + + // with booking in past + $this->createBooking( + $this->locationId, + $this->itemId, + strtotime( '-2 days', strtotime( self::CURRENT_DATE ) ), + strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ) + ); + $bookingCloakedId = $itemModel->getCloakedId(); + $this->assertNotEquals( $bookingCloakedId, $cloakedId ); + $this->assertEquals( $this->itemId, Item::getByCloakedId( $bookingCloakedId )->ID ); + + // test for invalid cloaked id + $this->assertNull( Item::getByCloakedId( 'invalid-cloaked-id' ) ); + } + public function testGetByLocation(): void { $this->assertEquals( [ $this->itemId ], diff --git a/tests/php/Service/BookingRuleTest.php b/tests/php/Service/BookingRuleTest.php index 50d0b9142..64f9f2a93 100644 --- a/tests/php/Service/BookingRuleTest.php +++ b/tests/php/Service/BookingRuleTest.php @@ -277,6 +277,58 @@ public function testCheckMaxBookingDays_earlyCancel() { $this->assertNull( BookingRule::checkMaxBookingDays( $allowedBooking, array( 4, 30 ) ) ); } + /** + * Regression test for #2158 + * @return void + */ + public function testCheckMaxBookingDays_unevenDays() { + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + $testBookingOne = new Booking( + get_post( + $this->createBooking( + $this->locationId, + $this->itemId, + strtotime( '+1 day' ), + strtotime( '+2 days' ), + '8:00 AM', + '12:00 PM', + 'confirmed', + $this->subscriberId + ) + ) + ); + $testBookingTwo = new Booking( + get_post( + $this->createBooking( + $this->locationId, + $this->itemId, + strtotime( '+4 day' ), + strtotime( '+5 days' ), + '8:00 AM', + '12:00 PM', + 'confirmed', + $this->subscriberId + ) + ) + ); + + $testBookingThree = new Booking( + get_post( + $this->createBooking( + $this->locationId, + $this->itemId, + strtotime( '+6 day' ), + strtotime( '+7 days' ), + '8:00 AM', + '12:00 PM', + 'unconfirmed', + $this->subscriberId + ) + ) + ); + $this->assertBookingsPresent( array( $testBookingOne, $testBookingTwo ), BookingRule::checkMaxBookingDays( $testBookingThree, array( 2, 25 ) ) ); + } + public function testCheckMaxBookingDaysPerWeek() { // rule settings $allowedPerWeek = 2; diff --git a/tests/php/View/CalendarTest.php b/tests/php/View/CalendarTest.php index e84f5080a..26433ce88 100644 --- a/tests/php/View/CalendarTest.php +++ b/tests/php/View/CalendarTest.php @@ -7,6 +7,7 @@ use CommonsBooking\Wordpress\CustomPostType\Item; use CommonsBooking\View\Calendar; use DateTime; +use Override; use SlopeIt\ClockMock\ClockMock; /** @@ -229,6 +230,7 @@ public function testRepetition() { } public function testRenderTable() { + \CommonsBooking\Wordpress\CustomPostType\Item::registerPostTypeTaxonomy(); $calendar = Calendar::renderTable( [] ); $item = new \CommonsBooking\Model\Item( $this->itemId ); $location = new \CommonsBooking\Model\Location( $this->locationId ); @@ -241,15 +243,11 @@ public function testRenderTable() { $taxonomyItem = new \CommonsBooking\Model\Item( $taxonomyItem ); $term = wp_create_term( 'Test Category', Item::getTaxonomyName() ); wp_set_post_terms( $taxonomyItem->ID, [ $term['term_id'] ], Item::getTaxonomyName() ); - $termObj = get_term_by( 'id', $term['term_id'], Item::getTaxonomyName() ); - $slug = $termObj->slug; - $timeframe = $this->createTimeframe( - $this->locationId, - $taxonomyItem->ID, - strtotime( '+' . self::timeframeStart . ' days midnight', $this->now ), - strtotime( '+' . self::timeframeEnd . ' days midnight', $this->now ) - ); - $calendar = Calendar::renderTable( [ 'itemcat' => $slug ] ); + $termObj = get_term_by( 'id', $term['term_id'], Item::getTaxonomyName() ); + $slug = $termObj->slug; + $this->createBookableTimeFrameIncludingCurrentDay( $location->ID, $taxonomyItem->ID ); + wp_cache_flush(); // for some reason, the tests were failing without this + $calendar = Calendar::renderTable( [ 'itemcat' => $slug ] ); $this->assertStringContainsString( $taxonomyItem->post_title, $calendar ); $this->assertStringNotContainsString( $item->post_title, $calendar ); @@ -474,8 +472,9 @@ private function createTimeframeFromConfig( string $name, int $itemId, int $loca } protected function setUp(): void { - parent::setUp(); + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + parent::setUp(); $this->now = time(); $this->timeframeId = $this->createTimeframe( $this->locationId, @@ -500,4 +499,9 @@ protected function setUp(): void { strtotime( '+300 days midnight' ) ); } + + protected function tearDown(): void { + ClockMock::reset(); + parent::tearDown(); + } } diff --git a/tests/php/View/ViewTest.php b/tests/php/View/ViewTest.php index 30982d9a3..0f59d0c9a 100644 --- a/tests/php/View/ViewTest.php +++ b/tests/php/View/ViewTest.php @@ -89,62 +89,54 @@ protected function setUp(): void { parent::setUp(); ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); - $now = time(); - $this->now = $now; - $this->item = new Item( $this->itemId ); $this->location = new Location( $this->locationId ); - - $timeframeId = $this->createTimeframe( + $timeframeId = $this->createTimeframe( $this->locationId, $this->itemId, - strtotime( '+5 days midnight', $now ), - strtotime( '+6 days midnight', $now ), + strtotime( '+5 days midnight', strtotime( self::CURRENT_DATE ) ), + strtotime( '+6 days midnight', strtotime( self::CURRENT_DATE ) ), ); // set booking days in advance update_post_meta( $timeframeId, \CommonsBooking\Model\Timeframe::META_TIMEFRAME_ADVANCE_BOOKING_DAYS, self::bookingDaysInAdvance ); - $timeframeId = $this->createTimeframe( $this->locationId, $this->itemId, - strtotime( '+2 days midnight', $now ), - strtotime( '+3 days midnight', $now ), - );// set booking days in advance + strtotime( '+2 days midnight', strtotime( self::CURRENT_DATE ) ), + strtotime( '+3 days midnight', strtotime( self::CURRENT_DATE ) ), + ); + // set booking days in advance update_post_meta( $timeframeId, \CommonsBooking\Model\Timeframe::META_TIMEFRAME_ADVANCE_BOOKING_DAYS, self::bookingDaysInAdvance ); - $timeframeId = $this->createTimeframe( $this->locationId, $this->itemId, - strtotime( '+8 days midnight', $now ), - strtotime( '+9 days midnight', $now ), + strtotime( '+8 days midnight', strtotime( self::CURRENT_DATE ) ), + strtotime( '+9 days midnight', strtotime( self::CURRENT_DATE ) ), ); // set booking days in advance update_post_meta( $timeframeId, \CommonsBooking\Model\Timeframe::META_TIMEFRAME_ADVANCE_BOOKING_DAYS, self::bookingDaysInAdvance ); - $timeframeId = $this->createTimeframe( $this->locationId, $this->itemId, - strtotime( '+12 days midnight', $now ), - strtotime( '+13 days midnight', $now ), + strtotime( '+12 days midnight', strtotime( self::CURRENT_DATE ) ), + strtotime( '+13 days midnight', strtotime( self::CURRENT_DATE ) ), ); // set booking days in advance update_post_meta( $timeframeId, \CommonsBooking\Model\Timeframe::META_TIMEFRAME_ADVANCE_BOOKING_DAYS, self::bookingDaysInAdvance ); - $timeframeId = $this->createTimeframe( $this->locationId, $this->itemId, - strtotime( '+14 days midnight', $now ), - strtotime( '+15 days midnight', $now ), + strtotime( '+14 days midnight', strtotime( self::CURRENT_DATE ) ), + strtotime( '+15 days midnight', strtotime( self::CURRENT_DATE ) ), ); // set booking days in advance update_post_meta( $timeframeId, \CommonsBooking\Model\Timeframe::META_TIMEFRAME_ADVANCE_BOOKING_DAYS, self::bookingDaysInAdvance ); - // this timeframe should not be in shortcode data, because it's out of 30 days advanced booking range $timeframeId = $this->createTimeframe( $this->locationId, $this->itemId, - strtotime( '+32 days midnight', $now ), - strtotime( '+33 days midnight', $now ), + strtotime( '+32 days midnight', strtotime( self::CURRENT_DATE ) ), + strtotime( '+33 days midnight', strtotime( self::CURRENT_DATE ) ), ); // set booking days in advance update_post_meta( $timeframeId, \CommonsBooking\Model\Timeframe::META_TIMEFRAME_ADVANCE_BOOKING_DAYS, self::bookingDaysInAdvance ); @@ -152,5 +144,6 @@ protected function setUp(): void { protected function tearDown(): void { parent::tearDown(); + ClockMock::reset(); } } diff --git a/tests/php/Wordpress/CustomPostType/BookingTest.php b/tests/php/Wordpress/CustomPostType/BookingTest.php index b1a5eff59..c453435de 100644 --- a/tests/php/Wordpress/CustomPostType/BookingTest.php +++ b/tests/php/Wordpress/CustomPostType/BookingTest.php @@ -50,7 +50,7 @@ public function testHandleBookingRequest_Default() { $this->assertFalse( $bookingModel->isConfirmed() ); // Case 2: We now confirm the booking. The booking should be confirmed - $newBookingId = Booking::handleBookingRequest( + $confirmedBookingId = Booking::handleBookingRequest( $this->itemId, $this->locationId, 'confirmed', @@ -61,10 +61,10 @@ public function testHandleBookingRequest_Default() { $postName, null ); - $this->bookingIds[] = $newBookingId; + $this->bookingIds[] = $confirmedBookingId; // the id should be the same - $this->assertEquals( $bookingId, $newBookingId ); + $this->assertEquals( $bookingId, $confirmedBookingId ); // we create a new model, just to be sure $bookingModel = new \CommonsBooking\Model\Booking( $bookingId ); $this->assertTrue( $bookingModel->isConfirmed() ); @@ -163,7 +163,7 @@ public function testHandleBookingRequest_Overbooking() { $this->assertFalse( $bookingModel->isConfirmed() ); // The overbooked days are not present anymore when confirming the booking cause they are only calculated on the Litepicker screen - $newBookingId = Booking::handleBookingRequest( + $confirmedBookingId = Booking::handleBookingRequest( $this->itemId, $this->locationId, 'confirmed', @@ -174,10 +174,10 @@ public function testHandleBookingRequest_Overbooking() { $postName, null ); - $this->bookingIds[] = $newBookingId; + $this->bookingIds[] = $confirmedBookingId; // the id should be the same - $this->assertEquals( $bookingId, $newBookingId ); + $this->assertEquals( $bookingId, $confirmedBookingId ); // we create a new model, just to be sure $bookingModel = new \CommonsBooking\Model\Booking( $bookingId ); $this->assertTrue( $bookingModel->isConfirmed() ); @@ -347,6 +347,65 @@ public function testHandleBookingRequest_deleted_confirm() { ); } + /** + * Regression test for #2217 + * When a booking is confirmed and another booking is created in the exact same timeframe afterwards, + * the previously confirmed booking was set to unconfirmed again. This test is in place to ensure that + * this does not happen again. + * + * @return void + */ + public function testHandleBookingRequest_noRecreation() { + $date = new \DateTime( self::CURRENT_DATE ); + $date->modify( '-1 day' ); + ClockMock::freeze( $date ); + // create regular booking through unconfirmed -> confirmed route + $bookingId = Booking::handleBookingRequest( + $this->itemId, + $this->locationId, + 'unconfirmed', + null, + null, + strtotime( self::CURRENT_DATE ), + strtotime( '+1 day', strtotime( self::CURRENT_DATE ) ), + null, + null + ); + $this->bookingIds[] = $bookingId; + + $bookingModel = new \CommonsBooking\Model\Booking( $bookingId ); + $postName = $bookingModel->post_name; + $confirmedBookingId = Booking::handleBookingRequest( + $this->itemId, + $this->locationId, + 'confirmed', + $bookingId, + null, + strtotime( self::CURRENT_DATE ), + strtotime( '+1 day', strtotime( self::CURRENT_DATE ) ), + $postName, + null + ); + $this->bookingIds[] = $confirmedBookingId; + + // attempt to recreate the booking, should keep status as "confirmed" because it was not explicitly cancelled + $bookingId = Booking::handleBookingRequest( + $this->itemId, + $this->locationId, + 'unconfirmed', + null, + null, + strtotime( self::CURRENT_DATE ), + strtotime( '+1 day', strtotime( self::CURRENT_DATE ) ), + null, + null + ); + $this->bookingIds[] = $bookingId; + + $bookingModel = new \CommonsBooking\Model\Booking( $bookingId ); + $this->assertTrue( $bookingModel->isConfirmed() ); + } + /** * This will check if the bookings can be exported through the WordPress personal data export tool * @return void diff --git a/tests/php/Wordpress/CustomPostType/RestrictionListColumnsTest.php b/tests/php/Wordpress/CustomPostType/RestrictionListColumnsTest.php new file mode 100644 index 000000000..be699d2d0 --- /dev/null +++ b/tests/php/Wordpress/CustomPostType/RestrictionListColumnsTest.php @@ -0,0 +1,38 @@ +createRestriction( + Restriction::TYPE_HINT, + $this->locationId, + $this->itemId, + strtotime( self::CURRENT_DATE ), + strtotime( '+1 day', strtotime( self::CURRENT_DATE ) ) + ); + $postType = new class() extends RestrictionPostType { + protected function getCustomFields(): array { + // Regression guard: getCustomFields() loads dynamic location and item options, + // so calling it for static type/state columns degrades list rendering performance. + throw new \RuntimeException( 'List columns must not build assignment options.' ); + } + }; + + ob_start(); + $postType->setCustomColumnsData( Restriction::META_TYPE, $restrictionId ); + $typeOutput = ob_get_clean(); + + ob_start(); + $postType->setCustomColumnsData( Restriction::META_STATE, $restrictionId ); + $stateOutput = ob_get_clean(); + + $this->assertSame( RestrictionPostType::getTypes()[ Restriction::TYPE_HINT ], $typeOutput ); + $this->assertSame( RestrictionPostType::getStates()[ Restriction::STATE_ACTIVE ], $stateOutput ); + } +} diff --git a/tests/php/Wordpress/CustomPostTypeTest.php b/tests/php/Wordpress/CustomPostTypeTest.php index 3543bee7f..671d4f9cd 100644 --- a/tests/php/Wordpress/CustomPostTypeTest.php +++ b/tests/php/Wordpress/CustomPostTypeTest.php @@ -110,6 +110,9 @@ public function createCBManager() { protected function setUp(): void { parent::setUp(); + Plugin::clearCache(); + wp_cache_flush(); + $this->dateFormatted = date( 'Y-m-d', strtotime( self::CURRENT_DATE ) ); $this->setUpBookingCodesTable(); @@ -142,6 +145,8 @@ protected function tearDown(): void { ClockMock::reset(); $this->tearDownAllPosts(); + Plugin::clearCache(); + wp_cache_flush(); $this->tearDownBookingCodesTable(); wp_logout();