diff --git a/.eslintignore b/.eslintignore index 49908faa97a4..59c83e97f089 100644 --- a/.eslintignore +++ b/.eslintignore @@ -6,6 +6,8 @@ libs/ client/public/service-worker.js client/public/ client/src/document/*.js +cloud-function/src/internal/ +cloud-function/**/*.js filecheck/*.js mdn/content/ tool/*.js diff --git a/.github/workflows/prod-build.yml b/.github/workflows/prod-build.yml index 8427633ea464..27dbb80b831c 100644 --- a/.github/workflows/prod-build.yml +++ b/.github/workflows/prod-build.yml @@ -49,13 +49,13 @@ on: WIP_PROJECT_ID: required: true +permissions: + contents: read + id-token: write + jobs: build: environment: prod - permissions: - contents: read - id-token: write - runs-on: ubuntu-latest-4core # Only run the scheduled workflows on the main repo. @@ -65,6 +65,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/checkout@v3 + if: ${{ ! vars.SKIP_BUILD || ! vars.SKIP_FUNCTION }} with: repository: mdn/content path: mdn/content @@ -87,6 +88,7 @@ jobs: echo "DEPLOYER_LOG_EACH_SUCCESSFUL_UPLOAD=${{ github.event.inputs.log_each_successful_upload || env.DEFAULT_LOG_EACH_SUCCESSFUL_UPLOAD }}" >> $GITHUB_ENV - uses: actions/checkout@v3 + if: ${{ ! vars.SKIP_BUILD || ! vars.SKIP_FUNCTION }} with: repository: mdn/translated-content path: mdn/translated-content @@ -94,33 +96,40 @@ jobs: fetch-depth: 0 - uses: actions/checkout@v3 + if: ${{ ! vars.SKIP_BUILD }} with: repository: mdn/mdn-contributor-spotlight path: mdn/mdn-contributor-spotlight - name: Setup Node.js environment + if: ${{ ! vars.SKIP_BUILD || ! vars.SKIP_FUNCTION }} uses: actions/setup-node@v3 with: node-version: 18 cache: yarn - name: Install all yarn packages + if: ${{ ! vars.SKIP_BUILD }} run: yarn --frozen-lockfile - name: Install Python + if: ${{ ! vars.SKIP_BUILD }} uses: actions/setup-python@v4 with: python-version: "3.10" - name: Install Python poetry + if: ${{ ! vars.SKIP_BUILD }} uses: snok/install-poetry@v1 - name: Install deployer + if: ${{ ! vars.SKIP_BUILD }} run: | cd deployer poetry install - name: Display Python & Poetry version + if: ${{ ! vars.SKIP_BUILD }} run: | python --version poetry --version @@ -135,6 +144,7 @@ jobs: run: cat /proc/cpuinfo - name: Build everything + if: ${{ ! vars.SKIP_BUILD }} env: # Remember, the mdn/content repo got cloned into `pwd` into a # sub-folder called "mdn/content" @@ -233,10 +243,11 @@ jobs: # Generate whatsdeployed files. yarn tool whatsdeployed --output client/build/_whatsdeployed/code.json - yarn tool whatsdeployed $CONTENT_ROOT --output client/build/_whatsdeployed/content.json + yarn tool whatsdeployed $CONTENT_ROOT --output client/build/_whatsdeployed/content.json yarn tool whatsdeployed $CONTENT_TRANSLATED_ROOT --output client/build/_whatsdeployed/translated-content.json - name: Deploy with deployer + if: ${{ ! (vars.SKIP_BUILD || vars.SKIP_AWS) }} env: GITHUB_SHA: ${{ env.GITHUB_SHA }} GITHUB_RUN_ID: ${{ env.GITHUB_RUN_ID }} @@ -273,32 +284,85 @@ jobs: poetry run deployer update-lambda-functions ./aws-lambda poetry run deployer search-index ../client/build - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v1-node16 + - name: Authenticate with GCP + if: ${{ ! vars.SKIP_BUILD }} + uses: google-github-actions/auth@v1 with: - aws-access-key-id: ${{ secrets.DEPLOYER_PROD_AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.DEPLOYER_PROD_AWS_SECRET_ACCESS_KEY }} - aws-region: us-east-1 + token_format: access_token + service_account: deploy-prod-content@${{ secrets.GCP_PROJECT_NAME }}.iam.gserviceaccount.com + workload_identity_provider: projects/${{ secrets.WIP_PROJECT_ID }}/locations/global/workloadIdentityPools/github-actions/providers/github-actions - - name: Invalidate CDN - env: - DISTRIBUTION: E2ZY2DGUN70EMI - PATHS: /* - run: aws cloudfront create-invalidation --distribution-id "$DISTRIBUTION" --paths "$PATHS" + - name: Setup gcloud + if: ${{ ! vars.SKIP_BUILD }} + uses: google-github-actions/setup-gcloud@v1 + + - name: Sync Yari Content + if: ${{ ! vars.SKIP_BUILD }} + run: |- + gsutil -q -m -h "Cache-Control: public, max-age=86400" cp -r client/build/static gs://${{ vars.GCP_BUCKET_NAME }}/main/static + gsutil -q -m -h "Cache-Control: public, max-age=86400" rsync -cdrj html,json,txt client/build gs://${{ vars.GCP_BUCKET_NAME }}/main - name: Authenticate with GCP + if: ${{ ! vars.SKIP_FUNCTION }} uses: google-github-actions/auth@v1 with: token_format: access_token - service_account: deploy-prod-content@${{ secrets.GCP_PROJECT_NAME }}.iam.gserviceaccount.com + service_account: deploy-prod-prod-mdn-ingress@${{ secrets.GCP_PROJECT_NAME }}.iam.gserviceaccount.com workload_identity_provider: projects/${{ secrets.WIP_PROJECT_ID }}/locations/global/workloadIdentityPools/github-actions/providers/github-actions - name: Setup gcloud + if: ${{ ! vars.SKIP_FUNCTION }} uses: google-github-actions/setup-gcloud@v1 + with: + install_components: "beta" - - name: Sync Yari Content + - name: Generate redirects map + if: ${{ ! vars.SKIP_FUNCTION }} + working-directory: cloud-function + env: + CONTENT_ROOT: ${{ github.workspace }}/mdn/content/files + CONTENT_TRANSLATED_ROOT: ${{ github.workspace }}/mdn/translated-content/files run: |- - gsutil -m -h "Cache-Control:public, max-age=86400" rsync -crj html,json,txt client/build gs://content-prod-mdn/main + npm ci + npm run build-redirects + + - name: Deploy Function + if: ${{ ! vars.SKIP_FUNCTION }} + run: |- + for region in europe-west1 us-west1 asia-east1; do + gcloud beta functions deploy mdn-prod-prod-$region \ + --gen2 \ + --runtime=nodejs18 \ + --region=$region \ + --source=cloud-function \ + --trigger-http \ + --allow-unauthenticated \ + --entry-point=mdnHandler \ + --concurrency=100 \ + --min-instances=10 \ + --max-instances=1000 \ + --memory=2GB \ + --timeout=30s \ + --set-env-vars="ORIGIN_MAIN=developer.mozilla.org" \ + --set-env-vars="ORIGIN_LIVE_SAMPLES=live-samples.mdn.mozilla.net" \ + --set-env-vars="SOURCE_CONTENT=https://storage.googleapis.com/${{ vars.GCP_BUCKET_NAME }}/main/" \ + --set-env-vars="SOURCE_API=https://api.developer.mozilla.org/" \ + --set-env-vars="SENTRY_DSN=${{ secrets.SENTRY_DSN_CLOUD_FUNCTION }}" \ + --set-env-vars="SENTRY_ENVIRONMENT=prod" \ + --set-env-vars="SENTRY_TRACES_SAMPLE_RATE=${{ vars.SENTRY_TRACES_SAMPLE_RATE }}" \ + --set-env-vars="SENTRY_RELEASE=${{ github.sha }}" \ + --set-secrets="KEVEL_SITE_ID=projects/${{ secrets.GCP_PROJECT_NAME }}/secrets/prod-kevel-site-id/versions/latest" \ + --set-secrets="KEVEL_NETWORK_ID=projects/${{ secrets.GCP_PROJECT_NAME }}/secrets/prod-kevel-network-id/versions/latest" \ + --set-secrets="SIGN_SECRET=projects/${{ secrets.GCP_PROJECT_NAME }}/secrets/prod-sign-secret/versions/latest" \ + --set-secrets="CARBON_ZONE_KEY=projects/${{ secrets.GCP_PROJECT_NAME }}/secrets/prod-carbon-zone-key/versions/latest" \ + --set-secrets="CARBON_FALLBACK_ENABLED=projects/${{ secrets.GCP_PROJECT_NAME }}/secrets/prod-fallback-enabled/versions/latest" \ + 2>&1 | sed "s/^/[$region] /" & + pids+=($!) + done + + for pid in "${pids[@]}"; do + wait $pid + done - name: Slack Notification if: failure() @@ -311,3 +375,38 @@ jobs: SLACK_MESSAGE: "Build failed :collision:" SLACK_FOOTER: "Powered by prod-build.yml" SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} + + invalidate: + environment: prod + needs: build + if: ${{ ! vars.SKIP_INVALIDATE }} + runs-on: ubuntu-latest + + steps: + - name: Configure AWS Credentials + if: ${{ ! vars.SKIP_AWS }} + uses: aws-actions/configure-aws-credentials@v1-node16 + with: + aws-access-key-id: ${{ secrets.DEPLOYER_PROD_AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.DEPLOYER_PROD_AWS_SECRET_ACCESS_KEY }} + aws-region: us-east-1 + + - name: Invalidate AWS CloudFront CDN + if: ${{ ! vars.SKIP_AWS }} + env: + DISTRIBUTION: E2ZY2DGUN70EMI + PATHS: /* + run: aws cloudfront create-invalidation --distribution-id "$DISTRIBUTION" --paths "$PATHS" + + - name: Authenticate with GCP + uses: google-github-actions/auth@v1 + with: + token_format: access_token + service_account: deploy-prod-prod-mdn-ingress@${{ secrets.GCP_PROJECT_NAME }}.iam.gserviceaccount.com + workload_identity_provider: projects/${{ secrets.WIP_PROJECT_ID }}/locations/global/workloadIdentityPools/github-actions/providers/github-actions + + - name: Setup gcloud + uses: google-github-actions/setup-gcloud@v1 + + - name: Invalidate Google Cloud CDN + run: gcloud compute url-maps invalidate-cdn-cache ${{ secrets.GCP_LOAD_BALANCER_NAME }} --path "/*" diff --git a/.github/workflows/stage-build.yml b/.github/workflows/stage-build.yml index 0a6a1d26a7ec..8698d97d48d2 100644 --- a/.github/workflows/stage-build.yml +++ b/.github/workflows/stage-build.yml @@ -49,13 +49,13 @@ on: WIP_PROJECT_ID: required: true +permissions: + contents: read + id-token: write + jobs: build: environment: stage - permissions: - contents: read - id-token: write - runs-on: ubuntu-latest-4core # Only run the scheduled workflows on the main repo. @@ -65,6 +65,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/checkout@v3 + if: ${{ ! vars.SKIP_BUILD || ! vars.SKIP_FUNCTION }} with: repository: mdn/content path: mdn/content @@ -87,6 +88,7 @@ jobs: echo "DEPLOYER_LOG_EACH_SUCCESSFUL_UPLOAD=${{ github.event.inputs.log_each_successful_upload || env.DEFAULT_LOG_EACH_SUCCESSFUL_UPLOAD }}" >> $GITHUB_ENV - uses: actions/checkout@v3 + if: ${{ ! vars.SKIP_BUILD || ! vars.SKIP_FUNCTION }} with: repository: mdn/translated-content path: mdn/translated-content @@ -94,33 +96,40 @@ jobs: fetch-depth: 0 - uses: actions/checkout@v3 + if: ${{ ! vars.SKIP_BUILD }} with: repository: mdn/mdn-contributor-spotlight path: mdn/mdn-contributor-spotlight - name: Setup Node.js environment + if: ${{ ! vars.SKIP_BUILD || ! vars.SKIP_FUNCTION }} uses: actions/setup-node@v3 with: node-version: 18 cache: yarn - name: Install all yarn packages + if: ${{ ! vars.SKIP_BUILD }} run: yarn --frozen-lockfile - name: Install Python + if: ${{ ! vars.SKIP_BUILD }} uses: actions/setup-python@v4 with: python-version: "3.10" - name: Install Python poetry + if: ${{ ! vars.SKIP_BUILD }} uses: snok/install-poetry@v1 - name: Install deployer + if: ${{ ! vars.SKIP_BUILD }} run: | cd deployer poetry install - name: Display Python & Poetry version + if: ${{ ! vars.SKIP_BUILD }} run: | python --version poetry --version @@ -135,6 +144,7 @@ jobs: run: cat /proc/cpuinfo - name: Build everything + if: ${{ ! vars.SKIP_BUILD }} env: # Remember, the mdn/content repo got cloned into `pwd` into a # sub-folder called "mdn/content" @@ -228,10 +238,11 @@ jobs: # Generate whatsdeployed files. yarn tool whatsdeployed --output client/build/_whatsdeployed/code.json - yarn tool whatsdeployed $CONTENT_ROOT --output client/build/_whatsdeployed/content.json + yarn tool whatsdeployed $CONTENT_ROOT --output client/build/_whatsdeployed/content.json yarn tool whatsdeployed $CONTENT_TRANSLATED_ROOT --output client/build/_whatsdeployed/translated-content.json - name: Deploy with deployer + if: ${{ ! (vars.SKIP_BUILD || vars.SKIP_AWS) }} env: GITHUB_SHA: ${{ env.GITHUB_SHA }} GITHUB_RUN_ID: ${{ env.GITHUB_RUN_ID }} @@ -270,32 +281,86 @@ jobs: poetry run deployer update-lambda-functions ./aws-lambda poetry run deployer search-index ../client/build - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v1-node16 + - name: Authenticate with GCP + if: ${{ ! vars.SKIP_BUILD }} + uses: google-github-actions/auth@v1 with: - aws-access-key-id: ${{ secrets.DEPLOYER_STAGE_AND_DEV_AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.DEPLOYER_STAGE_AND_DEV_AWS_SECRET_ACCESS_KEY }} - aws-region: us-east-1 + token_format: access_token + service_account: deploy-stage-content@${{ secrets.GCP_PROJECT_NAME }}.iam.gserviceaccount.com + workload_identity_provider: projects/${{ secrets.WIP_PROJECT_ID }}/locations/global/workloadIdentityPools/github-actions/providers/github-actions - - name: Invalidate CDN - env: - DISTRIBUTION: E2MLRMA1VTVDHX - PATHS: /* - run: aws cloudfront create-invalidation --distribution-id "$DISTRIBUTION" --paths "$PATHS" + - name: Setup gcloud + if: ${{ ! vars.SKIP_BUILD }} + uses: google-github-actions/setup-gcloud@v1 + + - name: Sync Yari Content + if: ${{ ! vars.SKIP_BUILD }} + run: |- + gsutil -q -m -h "Cache-Control: public, max-age=86400" cp -r client/build/static gs://${{ vars.GCP_BUCKET_NAME }}/main/static + gsutil -q -m -h "Cache-Control: public, max-age=86400" rsync -cdrj html,json,txt client/build gs://${{ vars.GCP_BUCKET_NAME }}/main + # Deploy Function - name: Authenticate with GCP + if: ${{ ! vars.SKIP_FUNCTION }} uses: google-github-actions/auth@v1 with: token_format: access_token - service_account: deploy-stage-content@${{ secrets.GCP_PROJECT_NAME }}.iam.gserviceaccount.com + service_account: deploy-stage-nonprod-mdn-ingre@${{ secrets.GCP_PROJECT_NAME }}.iam.gserviceaccount.com workload_identity_provider: projects/${{ secrets.WIP_PROJECT_ID }}/locations/global/workloadIdentityPools/github-actions/providers/github-actions - name: Setup gcloud + if: ${{ ! vars.SKIP_FUNCTION }} uses: google-github-actions/setup-gcloud@v1 + with: + install_components: "beta" - - name: Sync Yari Content + - name: Generate redirects map + if: ${{ ! vars.SKIP_FUNCTION }} + working-directory: cloud-function + env: + CONTENT_ROOT: ${{ github.workspace }}/mdn/content/files + CONTENT_TRANSLATED_ROOT: ${{ github.workspace }}/mdn/translated-content/files + run: | + npm ci + npm run build-redirects + + - name: Deploy Function + if: ${{ ! vars.SKIP_FUNCTION }} run: |- - gsutil -m -h "Cache-Control:public, max-age=86400" rsync -crj html,json,txt client/build gs://content-stage-mdn/main + for region in europe-west1 us-west1 asia-east1; do + gcloud beta functions deploy mdn-nonprod-stage-$region \ + --gen2 \ + --runtime=nodejs18 \ + --region=$region \ + --source=cloud-function \ + --trigger-http \ + --allow-unauthenticated \ + --entry-point=mdnHandler \ + --concurrency=100 \ + --min-instances=1 \ + --max-instances=100 \ + --memory=2GB \ + --timeout=30s \ + --set-env-vars="ORIGIN_MAIN=developer.allizom.org" \ + --set-env-vars="ORIGIN_LIVE_SAMPLES=live-samples.mdn.allizom.net" \ + --set-env-vars="SOURCE_CONTENT=https://storage.googleapis.com/${{ vars.GCP_BUCKET_NAME }}/main/" \ + --set-env-vars="SOURCE_API=https://api.developer.allizom.org/" \ + --set-env-vars="SENTRY_DSN=${{ secrets.SENTRY_DSN_CLOUD_FUNCTION }}" \ + --set-env-vars="SENTRY_ENVIRONMENT=stage" \ + --set-env-vars="SENTRY_TRACES_SAMPLE_RATE=${{ vars.SENTRY_TRACES_SAMPLE_RATE }}" \ + --set-env-vars="SENTRY_RELEASE=${{ github.sha }}" \ + --set-secrets="KEVEL_SITE_ID=projects/${{ secrets.GCP_PROJECT_NAME }}/secrets/stage-kevel-site-id/versions/latest" \ + --set-secrets="KEVEL_NETWORK_ID=projects/${{ secrets.GCP_PROJECT_NAME }}/secrets/stage-kevel-network-id/versions/latest" \ + --set-secrets="SIGN_SECRET=projects/${{ secrets.GCP_PROJECT_NAME }}/secrets/stage-sign-secret/versions/latest" \ + --set-secrets="CARBON_ZONE_KEY=projects/${{ secrets.GCP_PROJECT_NAME }}/secrets/stage-carbon-zone-key/versions/latest" \ + --set-secrets="CARBON_FALLBACK_ENABLED=projects/${{ secrets.GCP_PROJECT_NAME }}/secrets/stage-fallback-enabled/versions/latest" \ + 2>&1 | sed "s/^/[$region] /" & + pids+=($!) + done + + for pid in "${pids[@]}"; do + wait $pid + done - name: Slack Notification if: failure() @@ -308,3 +373,39 @@ jobs: SLACK_MESSAGE: "Build failed :collision:" SLACK_FOOTER: "Powered by stage-build.yml" SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} + + invalidate: + environment: stage + needs: build + if: ${{ ! vars.SKIP_INVALIDATE }} + runs-on: ubuntu-latest + + steps: + - name: Configure AWS Credentials + if: ${{ ! vars.SKIP_AWS }} + uses: aws-actions/configure-aws-credentials@v1-node16 + with: + aws-access-key-id: ${{ secrets.DEPLOYER_STAGE_AND_DEV_AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.DEPLOYER_STAGE_AND_DEV_AWS_SECRET_ACCESS_KEY }} + aws-region: us-east-1 + + - name: Invalidate CDN + if: ${{ ! vars.SKIP_AWS }} + env: + DISTRIBUTION: E2MLRMA1VTVDHX + PATHS: /* + run: aws cloudfront create-invalidation --distribution-id "$DISTRIBUTION" --paths "$PATHS" + + - name: Authenticate with GCP + uses: google-github-actions/auth@v1 + with: + token_format: access_token + service_account: deploy-stage-nonprod-mdn-ingre@${{ secrets.GCP_PROJECT_NAME }}.iam.gserviceaccount.com + workload_identity_provider: projects/${{ secrets.WIP_PROJECT_ID }}/locations/global/workloadIdentityPools/github-actions/providers/github-actions + + - name: Setup gcloud + uses: google-github-actions/setup-gcloud@v1 + + - name: Invalidate CDN + run: |- + gcloud compute url-maps invalidate-cdn-cache ${{ secrets.GCP_LOAD_BALANCER_NAME }} --path "/*" diff --git a/.prettierignore b/.prettierignore index 4694145ed555..20b223b967c3 100644 --- a/.prettierignore +++ b/.prettierignore @@ -29,3 +29,5 @@ _githistory.json /mdn/content popularities.json /client/public/service-worker.js +/cloud-function/src/internal/ +/cloud-function/**/*.js diff --git a/cloud-function/.env-dist b/cloud-function/.env-dist new file mode 100644 index 000000000000..79b10c57dd9b --- /dev/null +++ b/cloud-function/.env-dist @@ -0,0 +1,5 @@ +ORIGIN_MAIN="localhost" +ORIGIN_LIVE_SAMPLES="localhost" + +SOURCE_CONTENT=http://localhost:8100/ +SOURCE_RUMBA=http://localhost:8000/ diff --git a/cloud-function/.gcloudignore b/cloud-function/.gcloudignore new file mode 100644 index 000000000000..79b725a2ebad --- /dev/null +++ b/cloud-function/.gcloudignore @@ -0,0 +1,19 @@ +# This file specifies files that are *not* uploaded to Google Cloud +# using gcloud. It follows the same syntax as .gitignore, with the addition of +# "#!include" directives (which insert the entries of the given .gitignore-style +# file at that point). +# +# For more information, run: +# $ gcloud topic gcloudignore +# +.env* +.gcloudignore +# If you would like to upload your .git directory, .gitignore file or files +# from your .gitignore file, remove the corresponding line +# below: +.git +.gitignore + +#!include:.gitignore +!redirects.json +!src/internal/** diff --git a/cloud-function/.gitignore b/cloud-function/.gitignore new file mode 100644 index 000000000000..deb96650c7f6 --- /dev/null +++ b/cloud-function/.gitignore @@ -0,0 +1,7 @@ +node_modules +.env* +!.env-dist +*.log +redirects.json +src/**/*.js +src/internal diff --git a/cloud-function/Procfile b/cloud-function/Procfile new file mode 100644 index 000000000000..898c10d52fbb --- /dev/null +++ b/cloud-function/Procfile @@ -0,0 +1,2 @@ +proxy: npm run proxy +server: npm run server:watch diff --git a/cloud-function/README.md b/cloud-function/README.md new file mode 100644 index 000000000000..479fbb1629a4 --- /dev/null +++ b/cloud-function/README.md @@ -0,0 +1,54 @@ +# Cloud Function + +This is MDN's HTTP request handler, deployed using +[Cloud Functions](https://cloud.google.com/functions/) behind +[Cloud CDN](https://cloud.google.com/cdn/). It mostly proxies requests and +handles some special routes directly. + +## Quickstart + +Run `npm start` to serve the Cloud Function at http://localhost:7100/. + +By default, it will use your local `client/build` directory, serving it at +http://localhost:8100/, and proxy API requests to the stage API at +`https://developer.allizom.org/`. + +### How to use a local Rumba? + +Set `SOURCE_API=http://localhost:8000/` in your `.env.` + +### How to use Glean? + +To use Glean, the Cloud Function must be accessed via HTTPS. Otherwise the +Glean.js SDK throws an uncaught error that prevents execution of JavaScript. + +We recommend using [mkcert](https://github.com/FiloSottile/mkcert) to create a +locally-trusted development certificate. Add the key and certificate paths as +`HTTPS_KEY_FILE` and `HTTPS_CERT_FILE` variables to your `.env` file. This will +automatically enable an HTTPS proxy at https://localhost/ in addition to +`http://localhost:7100/`. + +## Environment variables + +The function uses the following environment variables: + +- `ORIGIN_MAIN` (default: `"localhost"`) - The expected `Host` header value for + requests to the main site. +- `ORIGIN_LIVE_SAMPLES` (default: `"localhost"`) - The expected `Host` header + value for requests to live samples. +- `SOURCE_CONTENT` (default: `"http://localhost:8100"`) - The URL at which the + client build is served. +- `SOURCE_API` (default: `"https://developer.allizom.org/"`) - The URL at which + the API is served. + +The placement handler uses the following environment variables: + +- `KEVEL_SITE_ID` (default: `0`) - Required for serving placements via Kevel. +- `KEVEL_NETWORK_ID` (default: `0`) - Required for serving placements via Kevel. +- `SIGN_SECRET` (default: `""`) - Required for serving placements. +- `CARBON_ZONE_KEY` (default: `""`) - Required for serving placements via + Carbon. +- `CARBON_FALLBACK_ENABLED` (default: `"false"`) - Whether fallback placements + should be served via Carbon. + +You can override the defaults by adding a `.env` file with `KEY=value` lines. diff --git a/cloud-function/package-lock.json b/cloud-function/package-lock.json new file mode 100644 index 000000000000..8b9cc145dd4b --- /dev/null +++ b/cloud-function/package-lock.json @@ -0,0 +1,3587 @@ +{ + "name": "mdn-function", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "mdn-function", + "version": "0.0.1", + "license": "MPL-2.0", + "dependencies": { + "@adzerk/decision-sdk": "^1.0.0-beta.20", + "@google-cloud/functions-framework": "^3.1.3", + "@sentry/serverless": "^7.47.0", + "@yari-internal/constants": "file:src/internal/constants", + "@yari-internal/fundamental-redirects": "file:src/internal/fundamental-redirects", + "@yari-internal/locale-utils": "file:src/internal/locale-utils", + "@yari-internal/pong": "file:src/internal/pong", + "@yari-internal/slug-utils": "file:src/internal/slug-utils", + "accept-language-parser": "^1.5.0", + "dotenv": "^16.0.3", + "express": "^4.18.2", + "http-proxy-middleware": "^2.0.6", + "sanitize-filename": "^1.6.3" + }, + "devDependencies": { + "@swc/core": "^1.3.38", + "@types/accept-language-parser": "^1.5.3", + "@types/http-proxy": "^1.17.10", + "@types/http-server": "^0.12.1", + "http-proxy": "^1.18.1", + "http-server": "^14.1.1", + "nodemon": "^2.0.22", + "npm-run-all": "^4.1.5", + "ts-node": "^10.9.1", + "typescript": "^4.9.5" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "../../../libs/constants": { + "extraneous": true + }, + "../../../libs/fundamental-redirects": { + "extraneous": true + }, + "../../../libs/locale-utils": { + "extraneous": true + }, + "../../../libs/slug-utils": { + "extraneous": true + }, + "../../libs/constants": { + "name": "@yari-internal/constants", + "version": "0.0.1", + "extraneous": true, + "license": "MPL-2.0" + }, + "../../libs/fundamental-redirects": { + "name": "@yari-internal/fundamental-redirects", + "version": "0.0.1", + "extraneous": true, + "license": "MPL-2.0" + }, + "../../libs/locale-utils": { + "name": "@yari-internal/locale-utils", + "version": "0.0.1", + "extraneous": true, + "license": "MPL-2.0" + }, + "../../libs/slug-utils": { + "name": "@yari-internal/slug-utils", + "version": "0.0.1", + "extraneous": true, + "license": "MPL-2.0", + "dependencies": { + "sanitize-filename": "^1.6.3" + } + }, + "../libs/constants": { + "extraneous": true + }, + "../libs/fundamental-redirects": { + "extraneous": true + }, + "../libs/locale-utils": { + "extraneous": true + }, + "../libs/slug-utils": { + "extraneous": true + }, + "node_modules/@adzerk/decision-sdk": { + "version": "1.0.0-beta.20", + "resolved": "https://registry.npmjs.org/@adzerk/decision-sdk/-/decision-sdk-1.0.0-beta.20.tgz", + "integrity": "sha512-IgEqZoELahKP0Q8oGYXpv50qf69D9PXeYWO7ImK+RLemYI0YsskE8Jr2ixRieXw0Dt77k4vSZz7FGMIChW0TsQ==", + "dependencies": { + "debug": "^4.1.1", + "form-data": "^2.5.1", + "isomorphic-unfetch": "^3.1.0" + } + }, + "node_modules/@adzerk/decision-sdk/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@adzerk/decision-sdk/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@google-cloud/functions-framework": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@google-cloud/functions-framework/-/functions-framework-3.1.3.tgz", + "integrity": "sha512-gNKEkbud/+QkS5+vn+UEvBX6L522OpyTOjM83/cR1JRhSsBTNn3kPe4L17ZQMjJHFvO9xIxF3FaPDTfOx1Umpw==", + "dependencies": { + "@types/express": "4.17.13", + "body-parser": "^1.18.3", + "cloudevents": "^6.0.0", + "express": "^4.16.4", + "minimist": "^1.2.7", + "on-finished": "^2.3.0", + "read-pkg-up": "^7.0.1", + "semver": "^7.3.5" + }, + "bin": { + "functions-framework": "build/src/main.js", + "functions-framework-nodejs": "build/src/main.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@sentry-internal/tracing": { + "version": "7.47.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.47.0.tgz", + "integrity": "sha512-udpHnCzF8DQsWf0gQwd0XFGp6Y8MOiwnl8vGt2ohqZGS3m1+IxoRLXsSkD8qmvN6KKDnwbaAvYnK0z0L+AW95g==", + "dependencies": { + "@sentry/core": "7.47.0", + "@sentry/types": "7.47.0", + "@sentry/utils": "7.47.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@sentry/core": { + "version": "7.47.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.47.0.tgz", + "integrity": "sha512-EFhZhKdMu7wKmWYZwbgTi8FNZ7Fq+HdlXiZWNz51Bqe3pHmfAkdHtAEs0Buo0v623MKA0CA4EjXIazGUM34XTg==", + "dependencies": { + "@sentry/types": "7.47.0", + "@sentry/utils": "7.47.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@sentry/node": { + "version": "7.47.0", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-7.47.0.tgz", + "integrity": "sha512-LTg2r5EV9yh4GLYDF+ViSltR9LLj/pcvk8YhANJcMO3Fp//xh8njcdU0FC2yNthUREawYDzAsVzLyCYJfV0H1A==", + "dependencies": { + "@sentry-internal/tracing": "7.47.0", + "@sentry/core": "7.47.0", + "@sentry/types": "7.47.0", + "@sentry/utils": "7.47.0", + "cookie": "^0.4.1", + "https-proxy-agent": "^5.0.0", + "lru_map": "^0.3.3", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@sentry/node/node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@sentry/serverless": { + "version": "7.47.0", + "resolved": "https://registry.npmjs.org/@sentry/serverless/-/serverless-7.47.0.tgz", + "integrity": "sha512-ROt35Kp1JiR/h37Cw6Fjv/MI3grZCKQSeA5SXpuJObwtpdHI5OIYULivsvwB6HieJBKhS/k3Iplnf/E39808Lg==", + "dependencies": { + "@sentry/node": "7.47.0", + "@sentry/types": "7.47.0", + "@sentry/utils": "7.47.0", + "@types/aws-lambda": "^8.10.62", + "@types/express": "^4.17.14", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@sentry/serverless/node_modules/@types/express": { + "version": "4.17.17", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", + "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@sentry/types": { + "version": "7.47.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.47.0.tgz", + "integrity": "sha512-GxXocplN0j1+uczovHrfkykl9wvkamDtWxlPUQgyGlbLGZn+UH1Y79D4D58COaFWGEZdSNKr62gZAjfEYu9nQA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@sentry/utils": { + "version": "7.47.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.47.0.tgz", + "integrity": "sha512-A89SaOLp6XeZfByeYo2C8Ecye/YAtk/gENuyOUhQEdMulI6mZdjqtHAp7pTMVgkBc/YNARVuoa+kR/IdRrTPkQ==", + "dependencies": { + "@sentry/types": "7.47.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@swc/core": { + "version": "1.3.38", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.38.tgz", + "integrity": "sha512-AiEVehRFws//AiiLx9DPDp1WDXt+yAoGD1kMYewhoF6QLdTz8AtYu6i8j/yAxk26L8xnegy0CDwcNnub9qenyQ==", + "dev": true, + "hasInstallScript": true, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.3.38", + "@swc/core-darwin-x64": "1.3.38", + "@swc/core-linux-arm-gnueabihf": "1.3.38", + "@swc/core-linux-arm64-gnu": "1.3.38", + "@swc/core-linux-arm64-musl": "1.3.38", + "@swc/core-linux-x64-gnu": "1.3.38", + "@swc/core-linux-x64-musl": "1.3.38", + "@swc/core-win32-arm64-msvc": "1.3.38", + "@swc/core-win32-ia32-msvc": "1.3.38", + "@swc/core-win32-x64-msvc": "1.3.38" + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.3.38", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.38.tgz", + "integrity": "sha512-4ZTJJ/cR0EsXW5UxFCifZoGfzQ07a8s4ayt1nLvLQ5QoB1GTAf9zsACpvWG8e7cmCR0L76R5xt8uJuyr+noIXA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.3.38", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.38.tgz", + "integrity": "sha512-Kim727rNo4Dl8kk0CR8aJQe4zFFtsT1TZGlNrNMUgN1WC3CRX7dLZ6ZJi/VVcTG1cbHp5Fp3mUzwHsMxEh87Mg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.3.38", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.38.tgz", + "integrity": "sha512-yaRdnPNU2enlJDRcIMvYVSyodY+Amhf5QuXdUbAj6rkDD6wUs/s9C6yPYrFDmoTltrG+nBv72mUZj+R46wVfSw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.3.38", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.38.tgz", + "integrity": "sha512-iNY1HqKo/wBSu3QOGBUlZaLdBP/EHcwNjBAqIzpb8J64q2jEN02RizqVW0mDxyXktJ3lxr3g7VW9uqklMeXbjQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.3.38", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.38.tgz", + "integrity": "sha512-LJCFgLZoPRkPCPmux+Q5ctgXRp6AsWhvWuY61bh5bIPBDlaG9pZk94DeHyvtiwT0syhTtXb2LieBOx6NqN3zeA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.3.38", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.38.tgz", + "integrity": "sha512-hRQGRIWHmv2PvKQM/mMV45mVXckM2+xLB8TYLLgUG66mmtyGTUJPyxjnJkbI86WNGqo18k+lAuMG2mn6QmzYwQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.3.38", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.38.tgz", + "integrity": "sha512-PTYSqtsIfPHLKDDNbueI5e0sc130vyHRiFOeeC6qqzA2FAiVvIxuvXHLr0soPvKAR1WyhtYmFB9QarcctemL2w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.3.38", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.38.tgz", + "integrity": "sha512-9lHfs5TPNs+QdkyZFhZledSmzBEbqml/J1rqPSb9Fy8zB6QlspixE6OLZ3nTlUOdoGWkcTTdrOn77Sd7YGf1AA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.3.38", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.38.tgz", + "integrity": "sha512-SbL6pfA2lqvDKnwTHwOfKWvfHAdcbAwJS4dBkFidr7BiPTgI5Uk8wAPcRb8mBECpmIa9yFo+N0cAFRvMnf+cNw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.3.38", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.38.tgz", + "integrity": "sha512-UFveLrL6eGvViOD8OVqUQa6QoQwdqwRvLtL5elF304OT8eCPZa8BhuXnWk25X8UcOyns8gFcb8Fhp3oaLi/Rlw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, + "node_modules/@types/accept-language-parser": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@types/accept-language-parser/-/accept-language-parser-1.5.3.tgz", + "integrity": "sha512-S8oM29O6nnRC3/+rwYV7GBYIIgNIZ52PCxqBG7OuItq9oATnYWy8FfeLKwvq5F7pIYjeeBSCI7y+l+Z9UEQpVQ==", + "dev": true + }, + "node_modules/@types/aws-lambda": { + "version": "8.10.114", + "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.114.tgz", + "integrity": "sha512-M8WpEGfC9iQ6V2Ccq6nGIXoQgeVc6z0Ngk8yCOL5V/TYIxshvb0MWQYLFFTZDesL0zmsoBc4OBjG9DB/4rei6w==" + }, + "node_modules/@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.13", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", + "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.33", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz", + "integrity": "sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "node_modules/@types/http-proxy": { + "version": "1.17.10", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.10.tgz", + "integrity": "sha512-Qs5aULi+zV1bwKAg5z1PWnDXWmsn+LxIvUGv6E2+OOMYhclZMO+OXd9pYVf2gLykf2I7IV2u7oTHwChPNsvJ7g==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/http-server": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/@types/http-server/-/http-server-0.12.1.tgz", + "integrity": "sha512-OJ8zs0o8JuHo92KCCsLq4BqkHPi1+Aj2yoPQXJ18LPUxOA1lqKfgBLtHNAQTwwPzeBqyo+HDkWD91MkfOGvNJg==", + "dev": true, + "dependencies": { + "@types/connect": "*" + } + }, + "node_modules/@types/mime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==" + }, + "node_modules/@types/node": { + "version": "18.14.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.5.tgz", + "integrity": "sha512-CRT4tMK/DHYhw1fcCEBwME9CSaZNclxfzVMe7GsO6ULSwsttbj70wSiX6rZdIjGblu93sTJxLdhNIT85KKI7Qw==" + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", + "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==" + }, + "node_modules/@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" + }, + "node_modules/@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" + }, + "node_modules/@types/serve-static": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz", + "integrity": "sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==", + "dependencies": { + "@types/mime": "*", + "@types/node": "*" + } + }, + "node_modules/@yari-internal/constants": { + "resolved": "src/internal/constants", + "link": true + }, + "node_modules/@yari-internal/fundamental-redirects": { + "resolved": "src/internal/fundamental-redirects", + "link": true + }, + "node_modules/@yari-internal/locale-utils": { + "resolved": "src/internal/locale-utils", + "link": true + }, + "node_modules/@yari-internal/pong": { + "resolved": "src/internal/pong", + "link": true + }, + "node_modules/@yari-internal/slug-utils": { + "resolved": "src/internal/slug-utils", + "link": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "node_modules/accept-language-parser": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/accept-language-parser/-/accept-language-parser-1.5.0.tgz", + "integrity": "sha512-QhyTbMLYo0BBGg1aWbeMG4ekWtds/31BrEU+DONOg/7ax23vxpL03Pb7/zBmha2v7vdD3AyzZVWBVGEZxKOXWw==" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agent-base/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/agent-base/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dev": true, + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "dev": true, + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/basic-auth/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 + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/cloudevents": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/cloudevents/-/cloudevents-6.0.4.tgz", + "integrity": "sha512-Vay81bTsutFkZxHnM2K0rev95d0x7aTZ3G+Bmm8/GnIzsVtGfeBkLcXFD4czZ08RoOn6POKl+rIXaBS+Xn+jIA==", + "dependencies": { + "ajv": "^8.11.0", + "ajv-formats": "^2.1.1", + "process": "^0.11.10", + "util": "^0.12.4", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=12 <20.0.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/corser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", + "integrity": "sha512-utCYNzRSQIZNPIcGZdQc92UVJYAhtGAteCFg0yRaFm8f0P+CPtyGyHXJcGXnffjCybUCEx3FQ2G7U3/o9eIkVQ==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/cross-spawn/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/define-properties": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "dev": true, + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dotenv": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", + "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.21.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.1.tgz", + "integrity": "sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.3", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.4", + "is-array-buffer": "^3.0.1", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.2", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/form-data": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "bin": { + "he": "bin/he" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" + }, + "node_modules/html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "dev": true, + "dependencies": { + "whatwg-encoding": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/http-server": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/http-server/-/http-server-14.1.1.tgz", + "integrity": "sha512-+cbxadF40UXd9T01zUHgA+rlo2Bg1Srer4+B4NwIHdaGxAGGv59nYRnGGDJ9LBk7alpS0US+J+bLLdQOOkJq4A==", + "dev": true, + "dependencies": { + "basic-auth": "^2.0.1", + "chalk": "^4.1.2", + "corser": "^2.0.1", + "he": "^1.2.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy": "^1.18.1", + "mime": "^1.6.0", + "minimist": "^1.2.6", + "opener": "^1.5.1", + "portfinder": "^1.0.28", + "secure-compare": "3.0.1", + "union": "~0.5.0", + "url-join": "^4.0.1" + }, + "bin": { + "http-server": "bin/http-server" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/http-server/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/http-server/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/http-server/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/http-server/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/http-server/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/http-server/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/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/internal-slot": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isomorphic-unfetch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/isomorphic-unfetch/-/isomorphic-unfetch-3.1.0.tgz", + "integrity": "sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==", + "dependencies": { + "node-fetch": "^2.6.1", + "unfetch": "^4.2.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "node_modules/load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/load-json-file/node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "dev": true, + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lru_map": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", + "integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==" + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "dev": true, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node_modules/node-fetch": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", + "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/nodemon": { + "version": "2.0.22", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", + "integrity": "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==", + "dev": true, + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/nodemon/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/nodemon/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-all": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", + "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "chalk": "^2.4.1", + "cross-spawn": "^6.0.5", + "memorystream": "^0.3.1", + "minimatch": "^3.0.4", + "pidtree": "^0.3.0", + "read-pkg": "^3.0.0", + "shell-quote": "^1.6.1", + "string.prototype.padend": "^3.0.0" + }, + "bin": { + "npm-run-all": "bin/npm-run-all/index.js", + "run-p": "bin/run-p/index.js", + "run-s": "bin/run-s/index.js" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/npm-run-all/node_modules/read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", + "dev": true, + "dependencies": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "dev": true, + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidtree": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", + "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", + "dev": true, + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/portfinder": { + "version": "1.0.32", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.32.tgz", + "integrity": "sha512-on2ZJVVDXRADWE6jnQaX0ioEylzgBpQk8r55NE4wjXW1ZxO+BgDlY6DXwj20i0V8eB4SenDQ00WEaxfiIQPcxg==", + "dev": true, + "dependencies": { + "async": "^2.6.4", + "debug": "^3.2.7", + "mkdirp": "^0.5.6" + }, + "engines": { + "node": ">= 0.12.0" + } + }, + "node_modules/portfinder/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/portfinder/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sanitize-filename": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz", + "integrity": "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==", + "dependencies": { + "truncate-utf8-bytes": "^1.0.0" + } + }, + "node_modules/secure-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", + "integrity": "sha512-AckIIV90rPDcBcglUwXPF3kg0P0qmPsPXAj6BBEENQE1p5yA1xfmDJzfi1Tappj37Pv2mVbKpL3Z1T+Nn7k1Qw==", + "dev": true + }, + "node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shell-quote": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.0.tgz", + "integrity": "sha512-QHsz8GgQIGKlRi24yFc6a6lN69Idnx634w49ay6+jA5yFh7a1UY+4Rp6HPx/L/1zcEDPEij8cIsiqR6bQsE5VQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/simple-update-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", + "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", + "dev": true, + "dependencies": { + "semver": "~7.0.0" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", + "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==" + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string.prototype.padend": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.4.tgz", + "integrity": "sha512-67otBXoksdjsnXXRUq+KMVTdlVRZ2af422Y0aTyTjVaoQkGr3mxl2Bc5emi7dOQ3OGVVQQskmLEWwFXwommpNw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "dependencies": { + "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/truncate-utf8-bytes": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", + "integrity": "sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==", + "dependencies": { + "utf8-byte-length": "^1.0.1" + } + }, + "node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, + "node_modules/unfetch": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/unfetch/-/unfetch-4.2.0.tgz", + "integrity": "sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==" + }, + "node_modules/union": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", + "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==", + "dev": true, + "dependencies": { + "qs": "^6.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-join": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", + "dev": true + }, + "node_modules/utf8-byte-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz", + "integrity": "sha512-4+wkEYLBbWxqTahEsWrhxepcoVOJ+1z5PGIjPZxRkytcdSUaNjIjBM7Xn8E+pdSuV7SzvWovBFA54FO0JSoqhA==" + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "dev": true, + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "src/internal/constants": { + "name": "@yari-internal/constants", + "version": "0.0.1", + "license": "MPL-2.0" + }, + "src/internal/fundamental-redirects": { + "name": "@yari-internal/fundamental-redirects", + "version": "0.0.1", + "license": "MPL-2.0" + }, + "src/internal/libs/constants": { + "version": "0.0.1", + "extraneous": true, + "license": "MPL-2.0" + }, + "src/internal/libs/locale-utils": { + "version": "0.0.1", + "extraneous": true, + "license": "MPL-2.0" + }, + "src/internal/libs/slug-utils": { + "version": "0.0.1", + "extraneous": true, + "license": "MPL-2.0", + "dependencies": { + "sanitize-filename": "^1.6.3" + } + }, + "src/internal/locale-utils": { + "name": "@yari-internal/locale-utils", + "version": "0.0.1", + "license": "MPL-2.0", + "dependencies": { + "accept-language-parser": "^1.5.0", + "cookie": "^0.5.0" + } + }, + "src/internal/pong": { + "name": "@yari-internal/pong", + "version": "0.0.1", + "license": "MPL-2.0", + "dependencies": { + "@adzerk/decision-sdk": "^1.0.0-beta.20", + "he": "^1.2.0" + } + }, + "src/internal/slug-utils": { + "name": "@yari-internal/slug-utils", + "version": "0.0.1", + "license": "MPL-2.0", + "dependencies": { + "sanitize-filename": "^1.6.3" + } + }, + "src/internals/fundamental-redirects": { + "extraneous": true + } + } +} diff --git a/cloud-function/package.json b/cloud-function/package.json new file mode 100644 index 000000000000..5f3a99a7e20b --- /dev/null +++ b/cloud-function/package.json @@ -0,0 +1,58 @@ +{ + "name": "mdn-function", + "version": "0.0.1", + "private": true, + "description": "", + "license": "MPL-2.0", + "author": "", + "type": "module", + "main": "src/index.js", + "scripts": { + "build": "tsc -b", + "build-redirects": "ts-node src/build-redirects.ts", + "copy-internal": "rm -rf ./src/internal && cp -R ../libs ./src/internal", + "gcp-build": "npm run build", + "prepare": "([ ! -e ../libs ] || npm run copy-internal)", + "proxy": "ts-node src/proxy.ts", + "server": "npm run build && functions-framework --target=mdnHandler", + "server:watch": "nodemon --exec npm run server", + "start": "nf start" + }, + "nodemonConfig": { + "ext": "json,ts", + "watch": [ + ".env", + "src" + ] + }, + "dependencies": { + "@adzerk/decision-sdk": "^1.0.0-beta.20", + "@google-cloud/functions-framework": "^3.1.3", + "@sentry/serverless": "^7.47.0", + "@yari-internal/constants": "file:src/internal/constants", + "@yari-internal/fundamental-redirects": "file:src/internal/fundamental-redirects", + "@yari-internal/locale-utils": "file:src/internal/locale-utils", + "@yari-internal/pong": "file:src/internal/pong", + "@yari-internal/slug-utils": "file:src/internal/slug-utils", + "accept-language-parser": "^1.5.0", + "dotenv": "^16.0.3", + "express": "^4.18.2", + "http-proxy-middleware": "^2.0.6", + "sanitize-filename": "^1.6.3" + }, + "devDependencies": { + "@swc/core": "^1.3.38", + "@types/accept-language-parser": "^1.5.3", + "@types/http-proxy": "^1.17.10", + "@types/http-server": "^0.12.1", + "http-proxy": "^1.18.1", + "http-server": "^14.1.1", + "nodemon": "^2.0.22", + "npm-run-all": "^4.1.5", + "ts-node": "^10.9.1", + "typescript": "^4.9.5" + }, + "engines": { + "node": ">=18.0.0" + } +} diff --git a/cloud-function/src/app.ts b/cloud-function/src/app.ts new file mode 100644 index 000000000000..e802f83f9978 --- /dev/null +++ b/cloud-function/src/app.ts @@ -0,0 +1,85 @@ +import express, { Request, Response } from "express"; +import { Router } from "express"; + +import { Origin } from "./env.js"; +import { proxyContent } from "./handlers/proxy-content.js"; +import { proxyKevel } from "./handlers/proxy-kevel.js"; +import { proxyApi } from "./handlers/proxy-api.js"; +import { handleStripePlans } from "./handlers/handle-stripe-plans.js"; +import { proxyTelemetry } from "./handlers/proxy-telemetry.js"; +import { lowercasePathname } from "./middlewares/lowercase-pathname.js"; +import { resolveIndexHTML } from "./middlewares/resolve-index-html.js"; +import { redirectLeadingSlash } from "./middlewares/redirect-leading-slash.js"; +import { redirectMovedPages } from "./middlewares/redirect-moved-pages.js"; +import { redirectFundamental } from "./middlewares/redirect-fundamental.js"; +import { redirectLocale } from "./middlewares/redirect-locale.js"; +import { redirectTrailingSlash } from "./middlewares/redirect-trailing-slash.js"; +import { requireOrigin } from "./middlewares/require-origin.js"; +import { notFound } from "./middlewares/not-found.js"; + +const router = Router(); +router.use(redirectLeadingSlash); +router.all( + "/api/v1/stripe/plans", + requireOrigin(Origin.main), + handleStripePlans +); +router.all( + ["/api/*", "/admin-api/*", "/events/fxa/*", "/users/fxa/*"], + requireOrigin(Origin.main), + proxyApi +); +router.all("/submit/mdn-yari/*", requireOrigin(Origin.main), proxyTelemetry); +router.all("/pong/*", requireOrigin(Origin.main), express.json(), proxyKevel); +router.all("/pimg/*", requireOrigin(Origin.main), proxyKevel); +router.get( + ["/assets/*", "/sitemaps/*", "/static/*", "/[^/]+.[^/]+"], + requireOrigin(Origin.main), + proxyContent +); +router.get("/", requireOrigin(Origin.main), redirectLocale); +router.get( + "/[^/]+/docs/*/_sample_.*.html", + requireOrigin(Origin.liveSamples), + resolveIndexHTML, + proxyContent +); +router.get( + "/[^/]+/docs/*/*.(png|jpeg|jpg|gif|svg|webp)", + requireOrigin(Origin.main, Origin.liveSamples), + resolveIndexHTML, + proxyContent +); +router.get( + "/[^/]+/docs/*", + requireOrigin(Origin.main), + redirectFundamental, + redirectLocale, + redirectTrailingSlash, + redirectMovedPages, + resolveIndexHTML, + proxyContent +); +router.get( + "/[^/]+/search-index.json", + requireOrigin(Origin.main), + lowercasePathname, + proxyContent +); +router.get( + "*", + requireOrigin(Origin.main), + redirectFundamental, + redirectLocale, + redirectTrailingSlash, + resolveIndexHTML, + proxyContent +); +router.all("*", notFound); + +export function createHandler() { + return async (req: Request, res: Response) => + router(req, res, () => { + /* noop */ + }); +} diff --git a/cloud-function/src/build-redirects.ts b/cloud-function/src/build-redirects.ts new file mode 100644 index 000000000000..f340d78b1307 --- /dev/null +++ b/cloud-function/src/build-redirects.ts @@ -0,0 +1,64 @@ +import * as fs from "node:fs"; +import * as path from "node:path"; +import { fileURLToPath } from "node:url"; + +import dotenv from "dotenv"; + +import { VALID_LOCALES } from "./internal/constants/index.js"; + +const dirname = path.dirname(fileURLToPath(import.meta.url)); + +const root = path.join(dirname, "..", ".."); +dotenv.config({ + path: path.join(root, process.env["ENV_FILE"] || ".env"), +}); + +function buildRedirectsMap() { + const redirectMap = new Map(); + + ["CONTENT_ROOT", "CONTENT_TRANSLATED_ROOT"].forEach((envvar) => { + if (!process.env[envvar]) { + console.error(`Missing ENV variable: ${envvar}`); + return; + } + + const base = process.env[envvar]; + console.log(`${envvar} = ${base}`); + + for (const locale of VALID_LOCALES.keys()) { + const path = [ + // Absolute path. + `${base}/${locale}/_redirects.txt`, + `${base}/files/${locale}/_redirects.txt`, + // Relative path. + `${root}/${base}/${locale}/_redirects.txt`, + `${root}/${base}/files/${locale}/_redirects.txt`, + ].find((path) => fs.existsSync(path)); + + if (path) { + const content = fs.readFileSync(path, "utf-8"); + const lines = content.split("\n"); + const redirectLines = lines.filter( + (line) => line.startsWith("/") && line.includes("\t") + ); + for (const redirectLine of redirectLines) { + const [source, target] = redirectLine.split("\t", 2); + if (source && target) { + redirectMap.set(source.toLowerCase(), target); + } + } + console.log(`- ${path}: ${redirectLines.length} redirects`); + } + } + }); + + const output = "redirects.json"; + + fs.writeFileSync(output, JSON.stringify(Object.fromEntries(redirectMap))); + + const count = redirectMap.size; + const kb = Math.round(fs.statSync(output).size / 1024); + console.log(`Wrote ${count} redirects in ${kb} KB.`); +} + +buildRedirectsMap(); diff --git a/cloud-function/src/constants.ts b/cloud-function/src/constants.ts new file mode 100644 index 000000000000..11579b469e4f --- /dev/null +++ b/cloud-function/src/constants.ts @@ -0,0 +1,5 @@ +export const DEFAULT_COUNTRY = "US"; + +export const PROXY_TIMEOUT = 20000; + +export const THIRTY_DAYS = 3600 * 24 * 30; diff --git a/cloud-function/src/env.ts b/cloud-function/src/env.ts new file mode 100644 index 000000000000..dd7c68f9c581 --- /dev/null +++ b/cloud-function/src/env.ts @@ -0,0 +1,79 @@ +import * as path from "node:path"; +import { cwd } from "node:process"; + +import dotenv from "dotenv"; +import { Request } from "express"; + +dotenv.config({ + path: path.join(cwd(), process.env["ENV_FILE"] || ".env"), +}); + +export const LOCAL_CONTENT = "http://localhost:8100/"; +export const LOCAL_RUMBA = "http://localhost:8000/"; + +export enum Origin { + main = "main", + liveSamples = "liveSamples", + unsafe = "unsafe", +} + +export enum Source { + content = "content", + liveSamples = "liveSamples", + api = "rumba", +} + +export const ORIGIN_MAIN: string = process.env["ORIGIN_MAIN"] || "localhost"; +export const ORIGIN_LIVE_SAMPLES: string = + process.env["ORIGIN_LIVE_SAMPLES"] || "localhost"; + +export function origin(req: Request): Origin { + switch (req.hostname) { + case ORIGIN_MAIN: + return Origin.main; + case ORIGIN_LIVE_SAMPLES: + return Origin.liveSamples; + default: + return Origin.unsafe; + } +} + +export const SOURCE_CONTENT: string = + process.env["SOURCE_CONTENT"] || LOCAL_CONTENT; +export const SOURCE_API: string = + process.env["SOURCE_API"] || "https://developer.allizom.org/"; + +export function getOriginFromRequest(req: Request): Origin { + if (req.hostname === ORIGIN_MAIN && !req.path.includes("/_sample_.")) { + return Origin.main; + } else if (req.hostname === ORIGIN_LIVE_SAMPLES) { + return Origin.liveSamples; + } else { + return Origin.unsafe; + } +} + +export function sourceUri(source: Source): string { + switch (source) { + case Source.content: + return SOURCE_CONTENT; + case Source.api: + return SOURCE_API; + default: + return ""; + } +} + +// Kevel. +export const KEVEL_SITE_ID = Number(process.env["KEVEL_SITE_ID"] ?? 0); +export const KEVEL_NETWORK_ID = Number(process.env["KEVEL_NETWORK_ID"] ?? 0); +export const SIGN_SECRET = process.env["SIGN_SECRET"] ?? ""; +export const CARBON_ZONE_KEY = process.env["CARBON_ZONE_KEY"] ?? ""; +export const CARBON_FALLBACK_ENABLED = Boolean( + JSON.parse(process.env["CARBON_FALLBACK_ENABLED"] || "false") +); + +// HTTPS. +// (Use https://github.com/FiloSottile/mkcert to generate a locally-trusted certificate.) +export const HTTPS_KEY_FILE = process.env["HTTPS_KEY_FILE"] ?? ""; +export const HTTPS_CERT_FILE = process.env["HTTPS_CERT_FILE"] ?? ""; diff --git a/cloud-function/src/handlers/handle-stripe-plans.ts b/cloud-function/src/handlers/handle-stripe-plans.ts new file mode 100644 index 000000000000..43e4281be772 --- /dev/null +++ b/cloud-function/src/handlers/handle-stripe-plans.ts @@ -0,0 +1,79 @@ +import acceptLanguageParser from "accept-language-parser"; +import { Request, Response } from "express"; + +import { ORIGIN_MAIN } from "../env.js"; +import { getRequestCountry } from "../utils.js"; +import stageLookup from "../stripe-plans/stage.js"; +import prodLookup from "../stripe-plans/prod.js"; + +interface PlanResult { + [name: string]: { monthlyPriceInCents: number; id: string }; +} +interface Result { + country: string; + currency: string; + plans: PlanResult; +} + +export async function handleStripePlans(req: Request, res: Response) { + const lookupData = + ORIGIN_MAIN === "developer.mozilla.org" ? prodLookup : stageLookup; + + const localeHeader = req.headers["accept-language"]; + + const countryCode = getRequestCountry(req); + + const supportedCurrency = lookupData.countryToCurrency[countryCode]; + + if (!supportedCurrency) { + return res.sendStatus(404).end(); + } + + const acceptLanguage = typeof localeHeader === "string" ? localeHeader : null; + + let supportedLanguageOrDefault; + if (acceptLanguage) { + //E.g "en-GB,en;q=0.7,it;q=0.3" - Takes 'en' + supportedLanguageOrDefault = + acceptLanguageParser.pick( + Object.keys(supportedCurrency.supportedLanguages), + acceptLanguage, + { loose: true } + ) || supportedCurrency.defaultLanguage; + } else { + supportedLanguageOrDefault = supportedCurrency.defaultLanguage; + } + + const key = `${supportedCurrency.currency}-${supportedLanguageOrDefault}`; + + const plans = lookupData.langCurrencyToPlans[key]; + if (!plans) { + return res.sendStatus(500).end(); + } + + const planResult: PlanResult = {}; + Object.entries(plans).forEach(([name, plan]) => { + let monthlyPriceInCents; + if (plan.recurring.interval === "year") { + monthlyPriceInCents = Math.floor(plan.unit_amount / 12); + } else { + monthlyPriceInCents = plan.unit_amount; + } + planResult[name] = { monthlyPriceInCents, id: plan.price_id }; + }); + + const result = { + country: countryCode, + currency: supportedCurrency.currency, + plans: planResult, + } satisfies Result; + + return ( + res + .status(200) + // Google CDN cannot partition by country, so we can only cache in browser. + .setHeader("Cache-Control", "private, max-age=86400") + .setHeader("Content-Type", "application/json") + .end(JSON.stringify(result)) + ); +} diff --git a/cloud-function/src/handlers/proxy-api.ts b/cloud-function/src/handlers/proxy-api.ts new file mode 100644 index 000000000000..24c03b0da2e6 --- /dev/null +++ b/cloud-function/src/handlers/proxy-api.ts @@ -0,0 +1,13 @@ +import { createProxyMiddleware, fixRequestBody } from "http-proxy-middleware"; + +import { Source, sourceUri } from "../env.js"; +import { PROXY_TIMEOUT } from "../constants.js"; + +export const proxyApi = createProxyMiddleware({ + target: sourceUri(Source.api), + changeOrigin: true, + autoRewrite: true, + proxyTimeout: PROXY_TIMEOUT, + xfwd: true, + onProxyReq: fixRequestBody, +}); diff --git a/cloud-function/src/handlers/proxy-content.ts b/cloud-function/src/handlers/proxy-content.ts new file mode 100644 index 000000000000..6001e914cbe7 --- /dev/null +++ b/cloud-function/src/handlers/proxy-content.ts @@ -0,0 +1,46 @@ +import { + createProxyMiddleware, + fixRequestBody, + responseInterceptor, +} from "http-proxy-middleware"; + +import { withContentResponseHeaders } from "../headers.js"; +import { Source, sourceUri } from "../env.js"; +import { PROXY_TIMEOUT } from "../constants.js"; +import { isLiveSampleURL } from "../utils.js"; + +const NOT_FOUND_PATH = "en-us/_spas/404.html"; + +let notFoundBuffer: ArrayBuffer; + +const target = sourceUri(Source.content); + +export const proxyContent = createProxyMiddleware({ + target, + changeOrigin: true, + autoRewrite: true, + proxyTimeout: PROXY_TIMEOUT, + xfwd: true, + selfHandleResponse: true, + onProxyReq: fixRequestBody, + onProxyRes: responseInterceptor( + async (responseBuffer, proxyRes, req, res) => { + withContentResponseHeaders(proxyRes, req, res); + if (proxyRes.statusCode === 404 && !isLiveSampleURL(req.url ?? "")) { + const tryHtml = await fetch(`${target}${req.url?.slice(1)}/index.html`); + if (tryHtml.ok) { + res.statusCode = 200; + res.setHeader("Content-Type", "text/html"); + return Buffer.from(await tryHtml.arrayBuffer()); + } else if (!notFoundBuffer) { + const response = await fetch(`${target}${NOT_FOUND_PATH}`); + notFoundBuffer = await response.arrayBuffer(); + } + res.setHeader("Content-Type", "text/html"); + return Buffer.from(notFoundBuffer); + } + + return responseBuffer; + } + ), +}); diff --git a/cloud-function/src/handlers/proxy-kevel.ts b/cloud-function/src/handlers/proxy-kevel.ts new file mode 100644 index 000000000000..e8d241fc6f1e --- /dev/null +++ b/cloud-function/src/handlers/proxy-kevel.ts @@ -0,0 +1,99 @@ +import * as url from "node:url"; + +import { Client } from "@adzerk/decision-sdk"; +import type { Request, Response } from "express"; + +import { Coder } from "../internal/pong/index.js"; +import { + createPongGetHandler, + createPongClickHandler, + createPongViewedHandler, + fetchImage, +} from "../internal/pong/index.js"; + +import * as env from "../env.js"; + +import { getRequestCountry } from "../utils.js"; + +const { KEVEL_SITE_ID, KEVEL_NETWORK_ID, SIGN_SECRET } = env; + +const siteId = KEVEL_SITE_ID; +const networkId = KEVEL_NETWORK_ID; +const client = new Client({ networkId, siteId }); + +const coder = new Coder(SIGN_SECRET); +const handleGet = createPongGetHandler(client, coder, env); +const handleClick = createPongClickHandler(coder); +const handleViewed = createPongViewedHandler(coder); + +export async function proxyKevel(req: Request, res: Response) { + const countryCode = getRequestCountry(req); + + const userAgent = req.headers["user-agent"] ?? ""; + + const parsedUrl = url.parse(req.url); + const pathname = parsedUrl.pathname ?? ""; + const search = parsedUrl.search ?? ""; + + if (pathname === "/pong/get") { + if (req.method !== "POST") { + return res.sendStatus(405).end(); + } + + const { body } = req; + const { statusCode: status, payload } = await handleGet( + body, + countryCode, + userAgent + ); + + return res + .status(status) + .setHeader("cache-control", "no-store") + .setHeader("content-type", "application/json") + .end(JSON.stringify(payload)); + } else if (req.path === "/pong/click") { + if (req.method !== "GET") { + return res.sendStatus(405).end(); + } + const params = new URLSearchParams(search); + try { + const { status, location } = await handleClick(params); + if (location && (status === 301 || status === 302)) { + return res.redirect(location); + } else { + return res.sendStatus(502).end(); + } + } catch (e) { + console.error(e); + } + } else if (pathname === "/pong/viewed") { + if (req.method !== "POST") { + return res.sendStatus(405).end(); + } + const params = new URLSearchParams(search); + try { + await handleViewed(params); + return res.sendStatus(201).end(); + } catch (e) { + console.error(e); + } + } else if (pathname.startsWith("/pimg/")) { + const src = coder.decodeAndVerify( + decodeURIComponent(pathname.substring("/pimg/".length)) + ); + if (!src) { + return res.sendStatus(400).end(); + } + const { buf, contentType } = await fetchImage(src); + return res + .status(200) + .set({ + "cache-control": "max-age=86400", + "content-type": contentType, + }) + .end(Buffer.from(buf)); + } + + return res.status(204).end(); +} diff --git a/cloud-function/src/handlers/proxy-telemetry.ts b/cloud-function/src/handlers/proxy-telemetry.ts new file mode 100644 index 000000000000..1040770df437 --- /dev/null +++ b/cloud-function/src/handlers/proxy-telemetry.ts @@ -0,0 +1,12 @@ +import { createProxyMiddleware, fixRequestBody } from "http-proxy-middleware"; + +import { PROXY_TIMEOUT } from "../constants.js"; + +export const proxyTelemetry = createProxyMiddleware({ + target: "https://incoming.telemetry.mozilla.org", + changeOrigin: true, + autoRewrite: true, + proxyTimeout: PROXY_TIMEOUT, + xfwd: true, + onProxyReq: fixRequestBody, +}); diff --git a/cloud-function/src/headers.ts b/cloud-function/src/headers.ts new file mode 100644 index 000000000000..1b051cebc9a9 --- /dev/null +++ b/cloud-function/src/headers.ts @@ -0,0 +1,104 @@ +import type { IncomingMessage, ServerResponse } from "node:http"; +import { Response } from "express"; + +import { CSP_VALUE } from "./internal/constants/index.js"; +import { isLiveSampleURL } from "./utils.js"; + +const HASHED_MAX_AGE = 60 * 60 * 24 * 365; +const DEFAULT_MAX_AGE = 60 * 60 * 24; + +const NO_CACHE_VALUE = "no-store, must-revalidate"; + +const HASHED_REGEX = /\.[a-f0-9]{8,32}\./; + +export function withContentResponseHeaders( + proxyRes: IncomingMessage, + req: IncomingMessage, + res: ServerResponse +): ServerResponse { + if (res.headersSent) { + console.warn( + `Cannot set content response headers. Headers already sent for: ${req.url}` + ); + return res; + } + + const url = req.url ?? ""; + + const isLiveSample = isLiveSampleURL(url); + + setContentResponseHeaders((name, value) => res.setHeader(name, value), { + csp: + !isLiveSample && + parseContentType(proxyRes.headers["content-type"]).startsWith( + "text/html" + ), + xFrame: !isLiveSample, + }); + + if (req.url?.endsWith("/sitemap.xml.gz")) { + res.setHeader("Content-Type", "application/xml"); + res.setHeader("Content-Encoding", "gzip"); + } + + const cacheControl = getCacheControl(proxyRes.statusCode ?? 0, url); + if (cacheControl) { + res.setHeader("Cache-Control", cacheControl); + } + + return res; +} + +function getCacheControl(statusCode: number, url: string) { + if ( + statusCode === 404 || + url.endsWith("/service-worker.js") || + url.includes("/_whatsdeployed/") + ) { + return NO_CACHE_VALUE; + } + + if (200 <= statusCode && statusCode < 300) { + const maxAge = getCacheMaxAgeForUrl(url); + return `public, max-age=${maxAge}`; + } + + return null; +} + +function getCacheMaxAgeForUrl(url: string): number { + const isHashed = HASHED_REGEX.test(url); + const maxAge = isHashed ? HASHED_MAX_AGE : DEFAULT_MAX_AGE; + + return maxAge; +} + +function parseContentType(value: unknown): string { + const firstValue = Array.isArray(value) ? value[0] ?? "" : value; + + return typeof firstValue === "string" ? firstValue : ""; +} + +export function withResponseHeaders( + res: Response, + options?: { csp?: boolean; xFrame?: boolean } +): Response { + setContentResponseHeaders( + (name, value) => res.set(name, value), + options ?? {} + ); + return res; +} + +export function setContentResponseHeaders( + setHeader: (name: string, value: string) => void, + { csp = true, xFrame = true }: { csp?: boolean; xFrame?: boolean } +): void { + [ + ["X-XSS-Protection", "1; mode=block"], + ["X-Content-Type-Options", "nosniff"], + ["Strict-Transport-Security", "max-age=63072000"], + ...(csp ? [["Content-Security-Policy", CSP_VALUE]] : []), + ...(xFrame ? [["X-Frame-Options", "DENY"]] : []), + ].forEach(([k, v]) => k && v && setHeader(k, v)); +} diff --git a/cloud-function/src/index.ts b/cloud-function/src/index.ts new file mode 100644 index 000000000000..789e9293275e --- /dev/null +++ b/cloud-function/src/index.ts @@ -0,0 +1,12 @@ +import { createHandler } from "./app.js"; +import { http } from "@google-cloud/functions-framework"; +import { GCPFunction } from "@sentry/serverless"; + +let handler = createHandler(); + +if (process.env["SENTRY_DSN"]) { + GCPFunction.init(); + handler = GCPFunction.wrapHttpFunction(handler); +} + +http("mdnHandler", handler); diff --git a/cloud-function/src/middlewares/lowercase-pathname.ts b/cloud-function/src/middlewares/lowercase-pathname.ts new file mode 100644 index 000000000000..3e87a55589d9 --- /dev/null +++ b/cloud-function/src/middlewares/lowercase-pathname.ts @@ -0,0 +1,19 @@ +import * as url from "node:url"; + +import { NextFunction, Request, Response } from "express"; + +export async function lowercasePathname( + req: Request, + _res: Response, + next: NextFunction +) { + const urlParsed = url.parse(req.url); + if (urlParsed.pathname) { + urlParsed.pathname = urlParsed.pathname.toLowerCase(); + req.url = url.format(urlParsed); + // Workaround for http-proxy-middleware v2 using `req.originalUrl`. + // See: https://github.com/chimurai/http-proxy-middleware/pull/731 + req.originalUrl = req.url; + } + next(); +} diff --git a/cloud-function/src/middlewares/not-found.ts b/cloud-function/src/middlewares/not-found.ts new file mode 100644 index 000000000000..71f0f6e17006 --- /dev/null +++ b/cloud-function/src/middlewares/not-found.ts @@ -0,0 +1,5 @@ +import type { Request, Response } from "express"; + +export async function notFound(_req: Request, res: Response) { + res.sendStatus(404).end(); +} diff --git a/cloud-function/src/middlewares/redirect-fundamental.ts b/cloud-function/src/middlewares/redirect-fundamental.ts new file mode 100644 index 000000000000..fe0a1c57e7ab --- /dev/null +++ b/cloud-function/src/middlewares/redirect-fundamental.ts @@ -0,0 +1,32 @@ +import { NextFunction, Request, Response } from "express"; + +import { THIRTY_DAYS } from "../constants.js"; +import { resolveFundamental } from "../internal/fundamental-redirects/index.js"; +import { redirect } from "../utils.js"; + +export async function redirectFundamental( + req: Request, + res: Response, + next: NextFunction +) { + const url = new URL(req.url, `${req.protocol}://${req.headers.host}`); + const requestURI = req.path; + + const fundamentalRedirect = resolveFundamental(requestURI); + if (fundamentalRedirect.url) { + // NOTE: The query string is not forwarded for document requests, + // as directed by their origin request policy, so it's safe to + // assume "request.querystring" is empty for document requests. + if (url.search) { + fundamentalRedirect.url += + (fundamentalRedirect.url.includes("?") ? "&" : "?") + + url.search.substring(1); + } + redirect(res, fundamentalRedirect.url, { + status: fundamentalRedirect.status, + cacheControlSeconds: THIRTY_DAYS, + }); + } + + next(); +} diff --git a/cloud-function/src/middlewares/redirect-leading-slash.ts b/cloud-function/src/middlewares/redirect-leading-slash.ts new file mode 100644 index 000000000000..acd50cae75fa --- /dev/null +++ b/cloud-function/src/middlewares/redirect-leading-slash.ts @@ -0,0 +1,28 @@ +import { NextFunction, Request, Response } from "express"; + +import { redirect } from "../utils.js"; + +// If the URL was something like `https://domain/en-US/search/`, our code +// would make a that a redirect to `/en-US/search` (stripping the trailing slash). +// But if it was `https://domain//en-US/search/` it *would* make a redirect +// to `//en-US/search`. +// However, if pathname starts with `//` the Location header might look +// relative but it's actually an absolute URL. +// A 302 redirect from `https://domain//evil.com/` actually ends open +// opening `https://evil.com/` in the browser, because the browser will +// treat `//evil.com/ == https://evil.com/`. +// Prevent any pathnames that start with a double //. +// This essentially means that a request for `GET /////anything` becomes +// 302 with `Location: /anything`. +export async function redirectLeadingSlash( + req: Request, + res: Response, + next: NextFunction +) { + const pathname = req.url; + if (pathname.startsWith("//")) { + return redirect(res, pathname.replace(/^\/+/g, "/")); + } + + next(); +} diff --git a/cloud-function/src/middlewares/redirect-locale.ts b/cloud-function/src/middlewares/redirect-locale.ts new file mode 100644 index 000000000000..413fcd46add6 --- /dev/null +++ b/cloud-function/src/middlewares/redirect-locale.ts @@ -0,0 +1,54 @@ +import { NextFunction, Request, Response } from "express"; + +import { getLocale } from "../internal/locale-utils/index.js"; +import { VALID_LOCALES } from "../internal/constants/index.js"; +import { redirect } from "../utils.js"; + +const NEEDS_LOCALE = /^\/(?:docs|search|settings|signin|signup|plus)(?:$|\/)/; + +export async function redirectLocale( + req: Request, + res: Response, + next: NextFunction +) { + const url = new URL(req.url, `${req.protocol}://${req.headers.host}`); + const requestURI = url.pathname; + const requestURILowerCase = requestURI.toLowerCase(); + const qs = url.search; + + // Do we need to insert the locale? If we do, trim a trailing slash + // to avoid a double redirect, except when requesting the home page. + if ( + requestURI === "" || + requestURI === "/" || + NEEDS_LOCALE.test(requestURILowerCase) + ) { + const path = requestURI.endsWith("/") + ? requestURI.slice(0, -1) + : requestURI; + // Note that "getLocale" only returns valid locales, never a retired locale. + const locale = getLocale(req); + // The only time we actually want a trailing slash is when the URL is just + // the locale. E.g. `/en-US/` (not `/en-US`) + return redirect(res, `/${locale}${path || "/"}` + qs); + } + + // At this point, the URI is guaranteed to start with a forward slash. + const uriParts = requestURI.split("/"); + const uriFirstPart = uriParts[1] ?? ""; + const uriFirstPartLC = uriFirstPart.toLowerCase(); + + // Do we need to redirect to the properly-cased locale? We also ensure + // here that requests for the home page have a trailing slash, while + // all others do not. + if ( + VALID_LOCALES.has(uriFirstPartLC) && + uriFirstPart !== VALID_LOCALES.get(uriFirstPartLC) + ) { + // Assemble the rest of the path without a trailing slash. + const extra = uriParts.slice(2).filter(Boolean).join("/"); + return redirect(res, `/${VALID_LOCALES.get(uriFirstPartLC)}/${extra}${qs}`); + } + + next(); +} diff --git a/cloud-function/src/middlewares/redirect-moved-pages.ts b/cloud-function/src/middlewares/redirect-moved-pages.ts new file mode 100644 index 000000000000..284dd60a12fd --- /dev/null +++ b/cloud-function/src/middlewares/redirect-moved-pages.ts @@ -0,0 +1,47 @@ +import { createRequire } from "node:module"; + +import { NextFunction, Request, Response } from "express"; + +import { decodePath } from "../internal/slug-utils/index.js"; +import { THIRTY_DAYS } from "../constants.js"; +import { redirect } from "../utils.js"; + +const require = createRequire(import.meta.url); +const REDIRECTS = require("../../redirects.json"); +const REDIRECT_SUFFIXES = ["/index.json", "/bcd.json", ""]; + +export async function redirectMovedPages( + req: Request, + res: Response, + next: NextFunction +) { + // Important: The requestURI may be URI-encoded. + // Example: + // - Encoded: /zh-TW/docs/AJAX:%E4%B8%8A%E6%89%8B%E7%AF%87 + // - Decoded: /zh-TW/docs/AJAX:上手篇 + const decodedUri = decodePath(req.path); + const decodedUriLC = decodedUri.toLowerCase(); + + // Redirect moved pages (see `_redirects.txt` in content/translated-content). + // Example: + // - Source: /zh-TW/docs/AJAX:上手篇 + // - Target: /zh-TW/docs/Web/Guide/AJAX/Getting_Started + for (const suffix of REDIRECT_SUFFIXES) { + if (!decodedUriLC.endsWith(suffix)) { + continue; + } + const source = decodedUriLC.substring( + 0, + decodedUriLC.length - suffix.length + ); + if (typeof REDIRECTS[source] == "string") { + const target = REDIRECTS[source] + suffix; + return redirect(res, target, { + status: 301, + cacheControlSeconds: THIRTY_DAYS, + }); + } + } + + next(); +} diff --git a/cloud-function/src/middlewares/redirect-trailing-slash.ts b/cloud-function/src/middlewares/redirect-trailing-slash.ts new file mode 100644 index 000000000000..397c8e423cdd --- /dev/null +++ b/cloud-function/src/middlewares/redirect-trailing-slash.ts @@ -0,0 +1,70 @@ +import { NextFunction, Request, Response } from "express"; + +import { THIRTY_DAYS } from "../constants.js"; +import { VALID_LOCALES } from "../internal/constants/index.js"; +import { redirect } from "../utils.js"; + +// Note that the keys of "VALID_LOCALES" are lowercase locales. +const LOCALE_URI_WITHOUT_TRAILING_SLASH = new Set( + [...VALID_LOCALES.keys()].map((locale) => `/${locale}`) +); +const LOCALE_URI_WITH_TRAILING_SLASH = new Set( + [...VALID_LOCALES.keys()].map((locale) => `/${locale}/`) +); +// TODO: The code that uses LEGACY_URI_NEEDING_TRAILING_SLASH should be +// temporary. For example, when we have moved to the Yari-built +// account settings page, we should add fundamental redirects +// for "/{locale}/account/?" and "/account/?" that redirect to +// "/{locale}/settings" and "/settings" respectively. The other +// cases can be either redirected or deleted eventually as well. +// The goal is to eventually remove the code that uses +// LEGACY_URI_NEEDING_TRAILING_SLASH. +const LEGACY_URI_NEEDING_TRAILING_SLASH = new RegExp( + `^(?:${[...LOCALE_URI_WITHOUT_TRAILING_SLASH].join( + "|" + )})?/(?:account|contribute|maintenance-mode|payments)/?$` +); + +export async function redirectTrailingSlash( + req: Request, + res: Response, + next: NextFunction +) { + const url = new URL(req.url, `${req.protocol}://${req.headers.host}`); + let requestURI = url.pathname; + const requestURILowerCase = requestURI.toLowerCase(); + const qs = url.search; + + // Handle cases related to the presence or absence of a trailing-slash. + if (LOCALE_URI_WITHOUT_TRAILING_SLASH.has(requestURILowerCase)) { + // Home page requests are the special case on MDN. They should + // always have a trailing slash. So a home page URL without a + // trailing slash should redirect to the same URL with a + // trailing slash. When the redirected home-page request is + // processed by this Lambda function, note that we'll remove + // the trailing slash before the request reaches S3 (see below). + return redirect(res, requestURI + "/" + qs, { + cacheControlSeconds: THIRTY_DAYS, + }); + } else if (LOCALE_URI_WITH_TRAILING_SLASH.has(requestURILowerCase)) { + // We've received a proper request for a locale's home page (i.e., + // it has a traling slash), but since that request will be served + // from S3, we need to strip the trailing slash before it reaches + // S3. This is required because we store the home pages in S3 as + // their path name itself, for example "en-us" for the English home + // page, not "en-us/index.html", which is what S3 would look for if + // we left the trailing slash. + requestURI = requestURI.slice(0, -1); + } else if ( + requestURI.endsWith("/") && + !LEGACY_URI_NEEDING_TRAILING_SLASH.test(requestURILowerCase) + ) { + // All other requests with a trailing slash should redirect to the + // same URL without the trailing slash. + return redirect(res, requestURI.slice(0, -1) + qs, { + cacheControlSeconds: THIRTY_DAYS, + }); + } + + next(); +} diff --git a/cloud-function/src/middlewares/require-origin.ts b/cloud-function/src/middlewares/require-origin.ts new file mode 100644 index 000000000000..0e2f2f58280e --- /dev/null +++ b/cloud-function/src/middlewares/require-origin.ts @@ -0,0 +1,15 @@ +import type { NextFunction, Request, Response } from "express"; + +import { Origin, getOriginFromRequest } from "../env.js"; + +export function requireOrigin(...expectedOrigins: Origin[]) { + return async (req: Request, res: Response, next: NextFunction) => { + const actualOrigin = getOriginFromRequest(req); + + if (expectedOrigins.includes(actualOrigin)) { + return next(); + } else { + return res.sendStatus(404).end(); + } + }; +} diff --git a/cloud-function/src/middlewares/resolve-index-html.ts b/cloud-function/src/middlewares/resolve-index-html.ts new file mode 100644 index 000000000000..d8d16028c447 --- /dev/null +++ b/cloud-function/src/middlewares/resolve-index-html.ts @@ -0,0 +1,34 @@ +import * as path from "node:path"; +import * as url from "node:url"; + +import { NextFunction, Request, Response } from "express"; + +import { slugToFolder } from "../internal/slug-utils/index.js"; + +// These are the only extensions in client/build/*/docs/*. +// `find client/build -type f | grep docs | xargs basename | sed 's/.*\.\([^.]*\)$/\1/' | sort | uniq` +const ASSET_REGEXP = /\.(gif|html|jpeg|jpg|json|png|svg|txt)$/i; + +function isAsset(url: string) { + return ASSET_REGEXP.test(url); +} + +export async function resolveIndexHTML( + req: Request, + _res: Response, + next: NextFunction +) { + const urlParsed = url.parse(req.url); + if (urlParsed.pathname) { + let pathname = slugToFolder(urlParsed.pathname); + if (!isAsset(pathname)) { + pathname = path.join(pathname, "index.html"); + } + urlParsed.pathname = pathname; + req.url = url.format(urlParsed); + // Workaround for http-proxy-middleware v2 using `req.originalUrl`. + // See: https://github.com/chimurai/http-proxy-middleware/pull/731 + req.originalUrl = req.url; + } + next(); +} diff --git a/cloud-function/src/proxy.ts b/cloud-function/src/proxy.ts new file mode 100644 index 000000000000..69fa27ecfa05 --- /dev/null +++ b/cloud-function/src/proxy.ts @@ -0,0 +1,57 @@ +import { readFileSync } from "node:fs"; +import { createServer } from "node:https"; +import httpProxy from "http-proxy"; +import httpServer from "http-server"; + +import { + HTTPS_CERT_FILE, + HTTPS_KEY_FILE, + LOCAL_CONTENT, + SOURCE_CONTENT, +} from "./env.js"; + +if (SOURCE_CONTENT === LOCAL_CONTENT) { + const url = new URL(LOCAL_CONTENT); + const contentServer = httpServer.createServer({ + root: "../client/build", + }); + contentServer.listen(url.port, () => + console.log(`client/build served on port ${url.port}`) + ); +} + +if (HTTPS_CERT_FILE && HTTPS_KEY_FILE) { + const proxy = httpProxy.createProxyServer({ + target: "http://localhost:5100", + }); + + const server = createServer( + { + key: readFileSync(HTTPS_KEY_FILE), + cert: readFileSync(HTTPS_CERT_FILE), + }, + (req, res) => proxy.web(req, res) + ); + + proxy.on("error", (err) => { + console.error("Proxy error:", err); + + // Restart the server + server.close(function () { + console.log("Server closed"); + server.listen(443, function () { + console.log("Server restarted"); + }); + }); + }); + + server.listen(443, () => console.log(`HTTPS proxy running on port 443`)); +} else { + console.log("HTTPS proxy disabled!"); + console.log( + "Note: Set HTTPS_CERT_FILE and HTTPS_KEY_FILE in .env to enable it." + ); + console.log( + "Hint: Use mkcert to create a locally-trusted development certificate." + ); +} diff --git a/cloud-function/src/stripe-plans/index.ts b/cloud-function/src/stripe-plans/index.ts new file mode 100644 index 000000000000..b9ce12359206 --- /dev/null +++ b/cloud-function/src/stripe-plans/index.ts @@ -0,0 +1,37 @@ +type CountryCode = string; +type LanguageCode = string; +type CurrencyCode = string; +type ProductId = string; +type PriceId = string; + +export interface Plan { + unit_amount: number; + currency: CurrencyCode; + product: ProductId; + recurring: { + interval: "month" | "year"; + }; + nickname: string; + lookup_key: string; + metadata: { [key: string]: string }; + price_id: PriceId; +} + +export interface LookupData { + countryToCurrency: { + [countryCode: CountryCode]: { + currency: CurrencyCode; + supportedLanguages: { + [languageCode: LanguageCode]: null | { + [key: string]: string; + }; + }; + defaultLanguage: LanguageCode; + }; + }; + langCurrencyToPlans: { + [langCurrencyCode: string]: { + [name: string]: Plan; + }; + }; +} diff --git a/cloud-function/src/stripe-plans/prod.ts b/cloud-function/src/stripe-plans/prod.ts new file mode 100644 index 000000000000..9e8698a83f65 --- /dev/null +++ b/cloud-function/src/stripe-plans/prod.ts @@ -0,0 +1,3709 @@ +import type { LookupData } from "./index.js"; + +const plans: LookupData = { + countryToCurrency: { + AS: { + currency: "usd", + supportedLanguages: { + en: null, + }, + defaultLanguage: "en", + }, + CA: { + currency: "usd", + supportedLanguages: { + en: null, + }, + defaultLanguage: "en", + }, + GB: { + currency: "usd", + supportedLanguages: { + en: null, + }, + defaultLanguage: "en", + }, + GU: { + currency: "usd", + supportedLanguages: { + en: null, + }, + defaultLanguage: "en", + }, + MP: { + currency: "usd", + supportedLanguages: { + en: null, + }, + defaultLanguage: "en", + }, + MY: { + currency: "usd", + supportedLanguages: { + en: null, + }, + defaultLanguage: "en", + }, + NZ: { + currency: "usd", + supportedLanguages: { + en: null, + }, + defaultLanguage: "en", + }, + PR: { + currency: "usd", + supportedLanguages: { + en: null, + }, + defaultLanguage: "en", + }, + SG: { + currency: "usd", + supportedLanguages: { + en: null, + }, + defaultLanguage: "en", + }, + US: { + currency: "usd", + supportedLanguages: { + en: null, + }, + defaultLanguage: "en", + }, + VI: { + currency: "usd", + supportedLanguages: { + en: null, + }, + defaultLanguage: "en", + }, + AT: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "de", + }, + BE: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "nl", + }, + CY: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "el", + }, + DE: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "de", + }, + EE: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "et", + }, + ES: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "es", + }, + FI: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "en", + }, + FR: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "fr", + }, + GR: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "el", + }, + IE: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "en", + }, + IT: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "it", + }, + LT: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "lt", + }, + LU: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "fr", + }, + LV: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "lv", + }, + MT: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "en", + }, + NL: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "nl", + }, + SE: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "en", + }, + SK: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "sk", + }, + SI: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "sl", + }, + PT: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "pt", + }, + CH: { + currency: "chf", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + }, + defaultLanguage: "de", + }, + }, + langCurrencyToPlans: { + "usd-en": { + mdn_plus_5m: { + unit_amount: 500, + currency: "usd", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - USD EN", + lookup_key: "usd-en-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:720bc80adfa6988d": "mdn_plus_5m", + "product:successActionButtonLabel": "Continue to MDN Plus", + "product:subtitle": "An MDN Premium Service", + "product:details:1": "Page notifications", + "product:details:2": "Collections of articles", + "product:details:3": "MDN offline", + }, + price_id: "price_1KeG02JNcmPzuWtR1oBrw8o6", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "usd", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - USD EN", + lookup_key: "usd-en-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:720bc80adfa6988d": "mdn_plus_5y", + "product:successActionButtonLabel": "Continue to MDN Plus", + "product:subtitle": "An MDN Premium Service", + "product:details:1": "Page notifications", + "product:details:2": "Collections of articles", + "product:details:3": "MDN offline", + }, + price_id: "price_1KeG02JNcmPzuWtRslZijhQu", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "usd", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - USD EN", + lookup_key: "usd-en-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:720bc80adfa6988d": "mdn_plus_10m", + "product:successActionButtonLabel": "Continue to MDN Plus", + "product:subtitle": "An MDN Premium Service", + "product:details:1": "Page notifications", + "product:details:2": "Collections of articles", + "product:details:3": "MDN offline", + }, + price_id: "price_1KeG02JNcmPzuWtRuAnIgNHh", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "usd", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - USD EN", + lookup_key: "usd-en-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:720bc80adfa6988d": "mdn_plus_10y", + "product:successActionButtonLabel": "Continue to MDN Plus", + "product:subtitle": "An MDN Premium Service", + "product:details:1": "Page notifications", + "product:details:2": "Collections of articles", + "product:details:3": "MDN offline", + }, + price_id: "price_1KeG02JNcmPzuWtRlrSiLTI6", + }, + }, + "eur-en": { + mdn_plus_5m: { + unit_amount: 500, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - EUR EN", + lookup_key: "eur-en-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:720bc80adfa6988d": "mdn_plus_5m", + "product:successActionButtonLabel": "Continue to MDN Plus", + "product:subtitle": "An MDN Premium Service", + "product:details:1": "Page notifications", + "product:details:2": "Collections of articles", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqeX9JNcmPzuWtRJNelT86c", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - EUR EN", + lookup_key: "eur-en-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:720bc80adfa6988d": "mdn_plus_5y", + "product:successActionButtonLabel": "Continue to MDN Plus", + "product:subtitle": "An MDN Premium Service", + "product:details:1": "Page notifications", + "product:details:2": "Collections of articles", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqeX9JNcmPzuWtR4dOStCqA", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - EUR EN", + lookup_key: "eur-en-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:720bc80adfa6988d": "mdn_plus_10m", + "product:successActionButtonLabel": "Continue to MDN Plus", + "product:subtitle": "An MDN Premium Service", + "product:details:1": "Page notifications", + "product:details:2": "Collections of articles", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqeXAJNcmPzuWtRjvfOVIUP", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - EUR EN", + lookup_key: "eur-en-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:720bc80adfa6988d": "mdn_plus_10y", + "product:successActionButtonLabel": "Continue to MDN Plus", + "product:subtitle": "An MDN Premium Service", + "product:details:1": "Page notifications", + "product:details:2": "Collections of articles", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqeXAJNcmPzuWtR5hwpwsUr", + }, + }, + "eur-de": { + mdn_plus_5m: { + unit_amount: 500, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - EUR DE", + lookup_key: "eur-de-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:720bc80adfa6988d": "mdn_plus_5m", + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqeXBJNcmPzuWtR7opydXog", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - EUR DE", + lookup_key: "eur-de-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:720bc80adfa6988d": "mdn_plus_5y", + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqeXBJNcmPzuWtRBSY6DGlv", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - EUR DE", + lookup_key: "eur-de-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:720bc80adfa6988d": "mdn_plus_10m", + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqeXBJNcmPzuWtRNWzQ6IX4", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - EUR DE", + lookup_key: "eur-de-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:720bc80adfa6988d": "mdn_plus_10y", + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqeXCJNcmPzuWtR5fl7C1tx", + }, + }, + "eur-el": { + mdn_plus_5m: { + unit_amount: 500, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - EUR EL", + lookup_key: "eur-el-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:720bc80adfa6988d": "mdn_plus_5m", + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + price_id: "price_1L5915JNcmPzuWtRMXzNAj50", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - EUR EL", + lookup_key: "eur-el-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:720bc80adfa6988d": "mdn_plus_5y", + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + price_id: "price_1L5916JNcmPzuWtRdYKhF10o", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - EUR EL", + lookup_key: "eur-el-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:720bc80adfa6988d": "mdn_plus_10m", + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + price_id: "price_1L5916JNcmPzuWtRkCVnoV9Y", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - EUR EL", + lookup_key: "eur-el-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:720bc80adfa6988d": "mdn_plus_10y", + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + price_id: "price_1L5917JNcmPzuWtRGcDOMndA", + }, + }, + "eur-es": { + mdn_plus_5m: { + unit_amount: 500, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - EUR ES", + lookup_key: "eur-es-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:720bc80adfa6988d": "mdn_plus_5m", + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + price_id: "price_1KqeXCJNcmPzuWtR05tPDWqA", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - EUR ES", + lookup_key: "eur-es-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:720bc80adfa6988d": "mdn_plus_5y", + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + price_id: "price_1KqeXCJNcmPzuWtR5yy0wlfO", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - EUR ES", + lookup_key: "eur-es-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:720bc80adfa6988d": "mdn_plus_10m", + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + price_id: "price_1KqeXDJNcmPzuWtRJAstOkqA", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - EUR ES", + lookup_key: "eur-es-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:720bc80adfa6988d": "mdn_plus_10y", + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + price_id: "price_1KqeXDJNcmPzuWtR8hPdxJiS", + }, + }, + "eur-et": { + mdn_plus_5m: { + unit_amount: 500, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - EUR ET", + lookup_key: "eur-et-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:720bc80adfa6988d": "mdn_plus_5m", + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + price_id: "price_1L5917JNcmPzuWtRXU88NcRx", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - EUR ET", + lookup_key: "eur-et-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:720bc80adfa6988d": "mdn_plus_5y", + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + price_id: "price_1L5918JNcmPzuWtRYHCMLCWR", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - EUR ET", + lookup_key: "eur-et-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:720bc80adfa6988d": "mdn_plus_10m", + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + price_id: "price_1L5918JNcmPzuWtRkS2tNVZC", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - EUR ET", + lookup_key: "eur-et-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:720bc80adfa6988d": "mdn_plus_10y", + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + price_id: "price_1L5918JNcmPzuWtRl47Ws8m0", + }, + }, + "eur-fr": { + mdn_plus_5m: { + unit_amount: 500, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - EUR FR", + lookup_key: "eur-fr-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:720bc80adfa6988d": "mdn_plus_5m", + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + price_id: "price_1KqeXDJNcmPzuWtRoL9NNeK4", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - EUR FR", + lookup_key: "eur-fr-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:720bc80adfa6988d": "mdn_plus_5y", + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + price_id: "price_1KqeXEJNcmPzuWtRTw1w8bX5", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - EUR FR", + lookup_key: "eur-fr-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:720bc80adfa6988d": "mdn_plus_10m", + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + price_id: "price_1KqeXEJNcmPzuWtR3WZLuJ6K", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - EUR FR", + lookup_key: "eur-fr-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:720bc80adfa6988d": "mdn_plus_10y", + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + price_id: "price_1KqeXEJNcmPzuWtR1kOfChz0", + }, + }, + "eur-it": { + mdn_plus_5m: { + unit_amount: 500, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - EUR IT", + lookup_key: "eur-it-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:720bc80adfa6988d": "mdn_plus_5m", + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqeXFJNcmPzuWtRUBiVlTVX", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - EUR IT", + lookup_key: "eur-it-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:720bc80adfa6988d": "mdn_plus_5y", + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqeXFJNcmPzuWtRjdDWnMU6", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - EUR IT", + lookup_key: "eur-it-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:720bc80adfa6988d": "mdn_plus_10m", + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqeXFJNcmPzuWtR2UJ1TVSG", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - EUR IT", + lookup_key: "eur-it-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:720bc80adfa6988d": "mdn_plus_10y", + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqeXGJNcmPzuWtR7cw3rh90", + }, + }, + "eur-lt": { + mdn_plus_5m: { + unit_amount: 500, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - EUR LT", + lookup_key: "eur-lt-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:720bc80adfa6988d": "mdn_plus_5m", + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + price_id: "price_1L5919JNcmPzuWtRvhirUtKK", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - EUR LT", + lookup_key: "eur-lt-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:720bc80adfa6988d": "mdn_plus_5y", + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + price_id: "price_1L5919JNcmPzuWtRNlOkp6pJ", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - EUR LT", + lookup_key: "eur-lt-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:720bc80adfa6988d": "mdn_plus_10m", + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + price_id: "price_1L591AJNcmPzuWtR0YIkMvZC", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - EUR LT", + lookup_key: "eur-lt-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:720bc80adfa6988d": "mdn_plus_10y", + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + price_id: "price_1L591AJNcmPzuWtRK2eZPpI9", + }, + }, + "eur-lv": { + mdn_plus_5m: { + unit_amount: 500, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - EUR LV", + lookup_key: "eur-lv-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:720bc80adfa6988d": "mdn_plus_5m", + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + price_id: "price_1L591AJNcmPzuWtRNotb24QG", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - EUR LV", + lookup_key: "eur-lv-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:720bc80adfa6988d": "mdn_plus_5y", + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + price_id: "price_1L591BJNcmPzuWtRS32AB1gs", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - EUR LV", + lookup_key: "eur-lv-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:720bc80adfa6988d": "mdn_plus_10m", + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + price_id: "price_1L591BJNcmPzuWtRk7skMZRp", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - EUR LV", + lookup_key: "eur-lv-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:720bc80adfa6988d": "mdn_plus_10y", + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + price_id: "price_1L591CJNcmPzuWtRUUa1ybJs", + }, + }, + "eur-nl": { + mdn_plus_5m: { + unit_amount: 500, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - EUR NL", + lookup_key: "eur-nl-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:720bc80adfa6988d": "mdn_plus_5m", + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqeXGJNcmPzuWtRcjH3vbwC", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - EUR NL", + lookup_key: "eur-nl-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:720bc80adfa6988d": "mdn_plus_5y", + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqeXGJNcmPzuWtRbycawcNr", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - EUR NL", + lookup_key: "eur-nl-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:720bc80adfa6988d": "mdn_plus_10m", + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqeXHJNcmPzuWtRxV9W8tIQ", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - EUR NL", + lookup_key: "eur-nl-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:720bc80adfa6988d": "mdn_plus_10y", + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqeXHJNcmPzuWtR9IvbHgFI", + }, + }, + "eur-pt": { + mdn_plus_5m: { + unit_amount: 500, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - EUR PT", + lookup_key: "eur-pt-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:720bc80adfa6988d": "mdn_plus_5m", + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + price_id: "price_1L591CJNcmPzuWtRhzqtQqRW", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - EUR PT", + lookup_key: "eur-pt-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:720bc80adfa6988d": "mdn_plus_5y", + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + price_id: "price_1L591CJNcmPzuWtRkmi7uEDk", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - EUR PT", + lookup_key: "eur-pt-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:720bc80adfa6988d": "mdn_plus_10m", + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + price_id: "price_1L591DJNcmPzuWtRQH8Mybz5", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - EUR PT", + lookup_key: "eur-pt-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:720bc80adfa6988d": "mdn_plus_10y", + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + price_id: "price_1L591DJNcmPzuWtRFZNp49Py", + }, + }, + "eur-sk": { + mdn_plus_5m: { + unit_amount: 500, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - EUR SK", + lookup_key: "eur-sk-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:720bc80adfa6988d": "mdn_plus_5m", + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + price_id: "price_1L591DJNcmPzuWtRdBWgbH2y", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - EUR SK", + lookup_key: "eur-sk-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:720bc80adfa6988d": "mdn_plus_5y", + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + price_id: "price_1L591EJNcmPzuWtRL5J0OPcy", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - EUR SK", + lookup_key: "eur-sk-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:720bc80adfa6988d": "mdn_plus_10m", + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + price_id: "price_1L591EJNcmPzuWtRKLalyUPd", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - EUR SK", + lookup_key: "eur-sk-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:720bc80adfa6988d": "mdn_plus_10y", + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + price_id: "price_1L591EJNcmPzuWtRwJobTR51", + }, + }, + "eur-sl": { + mdn_plus_5m: { + unit_amount: 500, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - EUR SL", + lookup_key: "eur-sl-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:720bc80adfa6988d": "mdn_plus_5m", + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + price_id: "price_1L591FJNcmPzuWtRIuDMHIsn", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - EUR SL", + lookup_key: "eur-sl-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:720bc80adfa6988d": "mdn_plus_5y", + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + price_id: "price_1L591FJNcmPzuWtRAa0tq6bw", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - EUR SL", + lookup_key: "eur-sl-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:720bc80adfa6988d": "mdn_plus_10m", + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + price_id: "price_1L591FJNcmPzuWtRduAZLny6", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - EUR SL", + lookup_key: "eur-sl-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:720bc80adfa6988d": "mdn_plus_10y", + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + price_id: "price_1L591GJNcmPzuWtRilCry5VT", + }, + }, + "eur-tr": { + mdn_plus_5m: { + unit_amount: 500, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - EUR TR", + lookup_key: "eur-tr-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:720bc80adfa6988d": "mdn_plus_5m", + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + price_id: "price_1L591GJNcmPzuWtRLDAVfALF", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - EUR TR", + lookup_key: "eur-tr-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:720bc80adfa6988d": "mdn_plus_5y", + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + price_id: "price_1L591GJNcmPzuWtRU3dE0gMp", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - EUR TR", + lookup_key: "eur-tr-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:720bc80adfa6988d": "mdn_plus_10m", + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + price_id: "price_1L591HJNcmPzuWtRCh2COINB", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "eur", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - EUR TR", + lookup_key: "eur-tr-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:720bc80adfa6988d": "mdn_plus_10y", + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + price_id: "price_1L591HJNcmPzuWtR6xBbf4ah", + }, + }, + "chf-en": { + mdn_plus_5m: { + unit_amount: 500, + currency: "chf", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - CHF EN", + lookup_key: "chf-en-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:720bc80adfa6988d": "mdn_plus_5m", + "product:successActionButtonLabel": "Continue to MDN Plus", + "product:subtitle": "An MDN Premium Service", + "product:details:1": "Page notifications", + "product:details:2": "Collections of articles", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqeXHJNcmPzuWtR4itTRF7Y", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "chf", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - CHF EN", + lookup_key: "chf-en-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:720bc80adfa6988d": "mdn_plus_5y", + "product:successActionButtonLabel": "Continue to MDN Plus", + "product:subtitle": "An MDN Premium Service", + "product:details:1": "Page notifications", + "product:details:2": "Collections of articles", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqeXIJNcmPzuWtRZJlZhXpW", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "chf", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - CHF EN", + lookup_key: "chf-en-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:720bc80adfa6988d": "mdn_plus_10m", + "product:successActionButtonLabel": "Continue to MDN Plus", + "product:subtitle": "An MDN Premium Service", + "product:details:1": "Page notifications", + "product:details:2": "Collections of articles", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqeXIJNcmPzuWtRKwoSofy2", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "chf", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - CHF EN", + lookup_key: "chf-en-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:720bc80adfa6988d": "mdn_plus_10y", + "product:successActionButtonLabel": "Continue to MDN Plus", + "product:subtitle": "An MDN Premium Service", + "product:details:1": "Page notifications", + "product:details:2": "Collections of articles", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqeXJJNcmPzuWtRDSDHSlAl", + }, + }, + "chf-de": { + mdn_plus_5m: { + unit_amount: 500, + currency: "chf", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - CHF DE", + lookup_key: "chf-de-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:720bc80adfa6988d": "mdn_plus_5m", + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqeXJJNcmPzuWtRDFlszhVO", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "chf", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - CHF DE", + lookup_key: "chf-de-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:720bc80adfa6988d": "mdn_plus_5y", + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqeXKJNcmPzuWtREcYZdrje", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "chf", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - CHF DE", + lookup_key: "chf-de-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:720bc80adfa6988d": "mdn_plus_10m", + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqeXKJNcmPzuWtRExRB58k0", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "chf", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - CHF DE", + lookup_key: "chf-de-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:720bc80adfa6988d": "mdn_plus_10y", + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqeXLJNcmPzuWtRtypFouG4", + }, + }, + "chf-fr": { + mdn_plus_5m: { + unit_amount: 500, + currency: "chf", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - CHF FR", + lookup_key: "chf-fr-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:720bc80adfa6988d": "mdn_plus_5m", + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + price_id: "price_1KqeXLJNcmPzuWtRyS2uTKyE", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "chf", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - CHF FR", + lookup_key: "chf-fr-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:720bc80adfa6988d": "mdn_plus_5y", + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + price_id: "price_1KqeXLJNcmPzuWtRbH6wD6sm", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "chf", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - CHF FR", + lookup_key: "chf-fr-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:720bc80adfa6988d": "mdn_plus_10m", + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + price_id: "price_1KqeXMJNcmPzuWtR46VuMNtb", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "chf", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - CHF FR", + lookup_key: "chf-fr-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:720bc80adfa6988d": "mdn_plus_10y", + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + price_id: "price_1KqeXMJNcmPzuWtR3bNmxM4C", + }, + }, + "chf-it": { + mdn_plus_5m: { + unit_amount: 500, + currency: "chf", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - CHF IT", + lookup_key: "chf-it-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:720bc80adfa6988d": "mdn_plus_5m", + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqeXMJNcmPzuWtRC7IJcwUD", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "chf", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - CHF IT", + lookup_key: "chf-it-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:720bc80adfa6988d": "mdn_plus_5y", + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqeXNJNcmPzuWtRSCJ2GbVn", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "chf", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - CHF IT", + lookup_key: "chf-it-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:720bc80adfa6988d": "mdn_plus_10m", + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqeXNJNcmPzuWtRRb5z07dQ", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "chf", + product: "prod_LKvr8fYGbBxcaZ", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - CHF IT", + lookup_key: "chf-it-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:720bc80adfa6988d": "mdn_plus_10y", + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqeXOJNcmPzuWtRMBae7104", + }, + }, + }, +}; + +export default plans; diff --git a/cloud-function/src/stripe-plans/stage.ts b/cloud-function/src/stripe-plans/stage.ts new file mode 100644 index 000000000000..16f030e04e63 --- /dev/null +++ b/cloud-function/src/stripe-plans/stage.ts @@ -0,0 +1,3861 @@ +import type { LookupData } from "./index.js"; + +const plans: LookupData = { + countryToCurrency: { + AS: { + currency: "usd", + supportedLanguages: { + en: null, + }, + defaultLanguage: "en", + }, + CA: { + currency: "usd", + supportedLanguages: { + en: null, + }, + defaultLanguage: "en", + }, + GB: { + currency: "usd", + supportedLanguages: { + en: null, + }, + defaultLanguage: "en", + }, + GU: { + currency: "usd", + supportedLanguages: { + en: null, + }, + defaultLanguage: "en", + }, + MP: { + currency: "usd", + supportedLanguages: { + en: null, + }, + defaultLanguage: "en", + }, + MY: { + currency: "usd", + supportedLanguages: { + en: null, + }, + defaultLanguage: "en", + }, + NZ: { + currency: "usd", + supportedLanguages: { + en: null, + }, + defaultLanguage: "en", + }, + PR: { + currency: "usd", + supportedLanguages: { + en: null, + }, + defaultLanguage: "en", + }, + SG: { + currency: "usd", + supportedLanguages: { + en: null, + }, + defaultLanguage: "en", + }, + US: { + currency: "usd", + supportedLanguages: { + en: null, + }, + defaultLanguage: "en", + }, + VI: { + currency: "usd", + supportedLanguages: { + en: null, + }, + defaultLanguage: "en", + }, + AT: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "de", + }, + BE: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "nl", + }, + CY: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "el", + }, + DE: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "de", + }, + EE: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "et", + }, + ES: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "es", + }, + FI: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "en", + }, + FR: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "fr", + }, + GR: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "el", + }, + IE: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "en", + }, + IT: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "it", + }, + LT: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "lt", + }, + LU: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "fr", + }, + LV: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "lv", + }, + MT: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "en", + }, + NL: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "nl", + }, + SE: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "en", + }, + SK: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "sk", + }, + SI: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "sl", + }, + PT: { + currency: "eur", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + el: { + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + es: { + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + et: { + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + lt: { + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + lv: { + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + nl: { + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + pt: { + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + sk: { + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + sl: { + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + tr: { + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + }, + defaultLanguage: "pt", + }, + CH: { + currency: "chf", + supportedLanguages: { + en: null, + de: { + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + fr: { + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + it: { + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + }, + defaultLanguage: "de", + }, + }, + langCurrencyToPlans: { + "usd-en": { + mdn_plus_5m: { + unit_amount: 500, + currency: "usd", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - USD EN", + lookup_key: "usd-en-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:b6f5727337fefe8e": "mdn_plus_5m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5m", + "capabilities:ed18cbc69ec23491": "mdn_plus_5m", + "product:successActionButtonLabel": "Continue to MDN Plus", + "product:subtitle": "An MDN Premium Service", + "product:details:1": "Page notifications", + "product:details:2": "Collections of articles", + "product:details:3": "MDN offline", + }, + price_id: "price_1JFoTYKb9q6OnNsLalexa03p", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "usd", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - USD EN", + lookup_key: "usd-en-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:b6f5727337fefe8e": "mdn_plus_5y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5y", + "capabilities:ed18cbc69ec23491": "mdn_plus_5y", + "product:successActionButtonLabel": "Continue to MDN Plus", + "product:subtitle": "An MDN Premium Service", + "product:details:1": "Page notifications", + "product:details:2": "Collections of articles", + "product:details:3": "MDN offline", + }, + price_id: "price_1JpIPwKb9q6OnNsLJLsIqMp7", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "usd", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - USD EN", + lookup_key: "usd-en-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:b6f5727337fefe8e": "mdn_plus_10m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10m", + "capabilities:ed18cbc69ec23491": "mdn_plus_10m", + "product:successActionButtonLabel": "Continue to MDN Plus", + "product:subtitle": "An MDN Premium Service", + "product:details:1": "Page notifications", + "product:details:2": "Collections of articles", + "product:details:3": "MDN offline", + }, + price_id: "price_1K6X7gKb9q6OnNsLi44HdLcC", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "usd", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - USD EN", + lookup_key: "usd-en-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:b6f5727337fefe8e": "mdn_plus_10y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10y", + "capabilities:ed18cbc69ec23491": "mdn_plus_10y", + "product:successActionButtonLabel": "Continue to MDN Plus", + "product:subtitle": "An MDN Premium Service", + "product:details:1": "Page notifications", + "product:details:2": "Collections of articles", + "product:details:3": "MDN offline", + }, + price_id: "price_1K6X8VKb9q6OnNsLFlUcEiu4", + }, + }, + "eur-en": { + mdn_plus_5m: { + unit_amount: 500, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - EUR EN", + lookup_key: "eur-en-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:b6f5727337fefe8e": "mdn_plus_5m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5m", + "capabilities:ed18cbc69ec23491": "mdn_plus_5m", + "product:successActionButtonLabel": "Continue to MDN Plus", + "product:subtitle": "An MDN Premium Service", + "product:details:1": "Page notifications", + "product:details:2": "Collections of articles", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqdudKb9q6OnNsLvZkMKGkx", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - EUR EN", + lookup_key: "eur-en-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:b6f5727337fefe8e": "mdn_plus_5y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5y", + "capabilities:ed18cbc69ec23491": "mdn_plus_5y", + "product:successActionButtonLabel": "Continue to MDN Plus", + "product:subtitle": "An MDN Premium Service", + "product:details:1": "Page notifications", + "product:details:2": "Collections of articles", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqdudKb9q6OnNsLJAJVh0rh", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - EUR EN", + lookup_key: "eur-en-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:b6f5727337fefe8e": "mdn_plus_10m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10m", + "capabilities:ed18cbc69ec23491": "mdn_plus_10m", + "product:successActionButtonLabel": "Continue to MDN Plus", + "product:subtitle": "An MDN Premium Service", + "product:details:1": "Page notifications", + "product:details:2": "Collections of articles", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqdudKb9q6OnNsLDYhWPIjT", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - EUR EN", + lookup_key: "eur-en-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:b6f5727337fefe8e": "mdn_plus_10y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10y", + "capabilities:ed18cbc69ec23491": "mdn_plus_10y", + "product:successActionButtonLabel": "Continue to MDN Plus", + "product:subtitle": "An MDN Premium Service", + "product:details:1": "Page notifications", + "product:details:2": "Collections of articles", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqdueKb9q6OnNsLDg4Toybn", + }, + }, + "eur-de": { + mdn_plus_5m: { + unit_amount: 500, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - EUR DE", + lookup_key: "eur-de-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:b6f5727337fefe8e": "mdn_plus_5m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5m", + "capabilities:ed18cbc69ec23491": "mdn_plus_5m", + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + price_id: "price_1Ko6oDKb9q6OnNsL3UV65T60", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - EUR DE", + lookup_key: "eur-de-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:b6f5727337fefe8e": "mdn_plus_5y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5y", + "capabilities:ed18cbc69ec23491": "mdn_plus_5y", + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + price_id: "price_1Ko6qAKb9q6OnNsLdsHFRRYW", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - EUR DE", + lookup_key: "eur-de-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:b6f5727337fefe8e": "mdn_plus_10m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10m", + "capabilities:ed18cbc69ec23491": "mdn_plus_10m", + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + price_id: "price_1Ko6rsKb9q6OnNsL9jMzlpUn", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - EUR DE", + lookup_key: "eur-de-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:b6f5727337fefe8e": "mdn_plus_10y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10y", + "capabilities:ed18cbc69ec23491": "mdn_plus_10y", + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + price_id: "price_1Ko6stKb9q6OnNsL4rnrw4Wn", + }, + }, + "eur-el": { + mdn_plus_5m: { + unit_amount: 500, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - EUR EL", + lookup_key: "eur-el-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:b6f5727337fefe8e": "mdn_plus_5m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5m", + "capabilities:ed18cbc69ec23491": "mdn_plus_5m", + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + price_id: "price_1L2tOPKb9q6OnNsLvZalzbLg", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - EUR EL", + lookup_key: "eur-el-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:b6f5727337fefe8e": "mdn_plus_5y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5y", + "capabilities:ed18cbc69ec23491": "mdn_plus_5y", + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + price_id: "price_1L2tOPKb9q6OnNsLkpUbrnJb", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - EUR EL", + lookup_key: "eur-el-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:b6f5727337fefe8e": "mdn_plus_10m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10m", + "capabilities:ed18cbc69ec23491": "mdn_plus_10m", + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + price_id: "price_1L2tOPKb9q6OnNsLvH7CfRM9", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - EUR EL", + lookup_key: "eur-el-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:b6f5727337fefe8e": "mdn_plus_10y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10y", + "capabilities:ed18cbc69ec23491": "mdn_plus_10y", + "product:successActionButtonLabel": "Μια Υπηρεσία MDN Premium", + "product:subtitle": "Ειδοποιήσεις σελίδας", + "product:details:1": "Συλλογή άρθρων", + "product:details:2": "MDN εκτός σύνδεσης", + "product:details:3": "Συνέχεια σε MDN Plus", + }, + price_id: "price_1L2tOQKb9q6OnNsLep9UMq1P", + }, + }, + "eur-es": { + mdn_plus_5m: { + unit_amount: 500, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - EUR ES", + lookup_key: "eur-es-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:b6f5727337fefe8e": "mdn_plus_5m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5m", + "capabilities:ed18cbc69ec23491": "mdn_plus_5m", + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + price_id: "price_1KqdugKb9q6OnNsL41ATLMv6", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - EUR ES", + lookup_key: "eur-es-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:b6f5727337fefe8e": "mdn_plus_5y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5y", + "capabilities:ed18cbc69ec23491": "mdn_plus_5y", + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + price_id: "price_1KqdugKb9q6OnNsLXv0GwhaT", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - EUR ES", + lookup_key: "eur-es-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:b6f5727337fefe8e": "mdn_plus_10m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10m", + "capabilities:ed18cbc69ec23491": "mdn_plus_10m", + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + price_id: "price_1KqdugKb9q6OnNsLF5ZHUiBP", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - EUR ES", + lookup_key: "eur-es-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:b6f5727337fefe8e": "mdn_plus_10y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10y", + "capabilities:ed18cbc69ec23491": "mdn_plus_10y", + "product:successActionButtonLabel": "Continuar a MDN Plus", + "product:subtitle": "Un servicio MDN prémium", + "product:details:1": "Notificaciones de página", + "product:details:2": "Colecciones de artículos", + "product:details:3": "MDN disponible sin conexión", + }, + price_id: "price_1KqduhKb9q6OnNsLfrNPlNDh", + }, + }, + "eur-et": { + mdn_plus_5m: { + unit_amount: 500, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - EUR ET", + lookup_key: "eur-et-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:b6f5727337fefe8e": "mdn_plus_5m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5m", + "capabilities:ed18cbc69ec23491": "mdn_plus_5m", + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + price_id: "price_1L2tOQKb9q6OnNsLYmRXAHtz", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - EUR ET", + lookup_key: "eur-et-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:b6f5727337fefe8e": "mdn_plus_5y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5y", + "capabilities:ed18cbc69ec23491": "mdn_plus_5y", + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + price_id: "price_1L2tORKb9q6OnNsLhVlLhMsM", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - EUR ET", + lookup_key: "eur-et-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:b6f5727337fefe8e": "mdn_plus_10m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10m", + "capabilities:ed18cbc69ec23491": "mdn_plus_10m", + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + price_id: "price_1L2tORKb9q6OnNsLEqTNWbxw", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - EUR ET", + lookup_key: "eur-et-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:b6f5727337fefe8e": "mdn_plus_10y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10y", + "capabilities:ed18cbc69ec23491": "mdn_plus_10y", + "product:successActionButtonLabel": "MDN Premium Service", + "product:subtitle": "Lehe teavitused", + "product:details:1": "Artiklite kollektsioonid", + "product:details:2": "Liikuge edasi MDN Plus teenuse juurde", + "product:details:3": "MDN offline", + }, + price_id: "price_1L2tOSKb9q6OnNsLdujiVlew", + }, + }, + "eur-fr": { + mdn_plus_5m: { + unit_amount: 500, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - EUR FR", + lookup_key: "eur-fr-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:b6f5727337fefe8e": "mdn_plus_5m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5m", + "capabilities:ed18cbc69ec23491": "mdn_plus_5m", + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + price_id: "price_1KqduhKb9q6OnNsLOPbGN60q", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - EUR FR", + lookup_key: "eur-fr-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:b6f5727337fefe8e": "mdn_plus_5y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5y", + "capabilities:ed18cbc69ec23491": "mdn_plus_5y", + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + price_id: "price_1KqduhKb9q6OnNsL2Iio3oSP", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - EUR FR", + lookup_key: "eur-fr-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:b6f5727337fefe8e": "mdn_plus_10m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10m", + "capabilities:ed18cbc69ec23491": "mdn_plus_10m", + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + price_id: "price_1KqduiKb9q6OnNsLzF5Ca5LV", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - EUR FR", + lookup_key: "eur-fr-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:b6f5727337fefe8e": "mdn_plus_10y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10y", + "capabilities:ed18cbc69ec23491": "mdn_plus_10y", + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + price_id: "price_1KqduiKb9q6OnNsLH0G5Lmvk", + }, + }, + "eur-it": { + mdn_plus_5m: { + unit_amount: 500, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - EUR IT", + lookup_key: "eur-it-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:b6f5727337fefe8e": "mdn_plus_5m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5m", + "capabilities:ed18cbc69ec23491": "mdn_plus_5m", + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqduiKb9q6OnNsL6Amq5kOo", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - EUR IT", + lookup_key: "eur-it-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:b6f5727337fefe8e": "mdn_plus_5y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5y", + "capabilities:ed18cbc69ec23491": "mdn_plus_5y", + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqdujKb9q6OnNsLhdfctEHd", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - EUR IT", + lookup_key: "eur-it-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:b6f5727337fefe8e": "mdn_plus_10m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10m", + "capabilities:ed18cbc69ec23491": "mdn_plus_10m", + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqdujKb9q6OnNsLPFNYmZdu", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - EUR IT", + lookup_key: "eur-it-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:b6f5727337fefe8e": "mdn_plus_10y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10y", + "capabilities:ed18cbc69ec23491": "mdn_plus_10y", + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqdukKb9q6OnNsLje4nw89h", + }, + }, + "eur-lt": { + mdn_plus_5m: { + unit_amount: 500, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - EUR LT", + lookup_key: "eur-lt-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:b6f5727337fefe8e": "mdn_plus_5m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5m", + "capabilities:ed18cbc69ec23491": "mdn_plus_5m", + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + price_id: "price_1L2tOSKb9q6OnNsLcj6DVCay", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - EUR LT", + lookup_key: "eur-lt-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:b6f5727337fefe8e": "mdn_plus_5y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5y", + "capabilities:ed18cbc69ec23491": "mdn_plus_5y", + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + price_id: "price_1L2tOSKb9q6OnNsLMXAdyweB", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - EUR LT", + lookup_key: "eur-lt-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:b6f5727337fefe8e": "mdn_plus_10m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10m", + "capabilities:ed18cbc69ec23491": "mdn_plus_10m", + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + price_id: "price_1L2tOTKb9q6OnNsLeLloEB9W", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - EUR LT", + lookup_key: "eur-lt-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:b6f5727337fefe8e": "mdn_plus_10y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10y", + "capabilities:ed18cbc69ec23491": "mdn_plus_10y", + "product:successActionButtonLabel": "MDN „Premium“ paslauga", + "product:subtitle": "Puslapio pranešimai", + "product:details:1": "Straipsnių rinkiniai", + "product:details:2": "Tęsti su „MDN Plus“", + "product:details:3": "MDN neprisijungus", + }, + price_id: "price_1L2tOTKb9q6OnNsLtyHtZTZs", + }, + }, + "eur-lv": { + mdn_plus_5m: { + unit_amount: 500, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - EUR LV", + lookup_key: "eur-lv-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:b6f5727337fefe8e": "mdn_plus_5m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5m", + "capabilities:ed18cbc69ec23491": "mdn_plus_5m", + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + price_id: "price_1L2tOTKb9q6OnNsLavSzI6Rc", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - EUR LV", + lookup_key: "eur-lv-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:b6f5727337fefe8e": "mdn_plus_5y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5y", + "capabilities:ed18cbc69ec23491": "mdn_plus_5y", + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + price_id: "price_1L2tOUKb9q6OnNsLkzLwkTdw", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - EUR LV", + lookup_key: "eur-lv-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:b6f5727337fefe8e": "mdn_plus_10m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10m", + "capabilities:ed18cbc69ec23491": "mdn_plus_10m", + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + price_id: "price_1L2tOUKb9q6OnNsLLJLA6cln", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - EUR LV", + lookup_key: "eur-lv-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:b6f5727337fefe8e": "mdn_plus_10y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10y", + "capabilities:ed18cbc69ec23491": "mdn_plus_10y", + "product:successActionButtonLabel": "MDN Premium pakalpojums", + "product:subtitle": "Lapas paziņojumi", + "product:details:1": "Rakstu apkopojumi", + "product:details:2": "Turpināt ar MDN Plus", + "product:details:3": "MDN bezsaistē", + }, + price_id: "price_1L2tOUKb9q6OnNsLV6ORmdfX", + }, + }, + "eur-nl": { + mdn_plus_5m: { + unit_amount: 500, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - EUR NL", + lookup_key: "eur-nl-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:b6f5727337fefe8e": "mdn_plus_5m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5m", + "capabilities:ed18cbc69ec23491": "mdn_plus_5m", + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqdukKb9q6OnNsLjjA8mTpM", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - EUR NL", + lookup_key: "eur-nl-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:b6f5727337fefe8e": "mdn_plus_5y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5y", + "capabilities:ed18cbc69ec23491": "mdn_plus_5y", + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqdukKb9q6OnNsLPCtBqPcw", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - EUR NL", + lookup_key: "eur-nl-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:b6f5727337fefe8e": "mdn_plus_10m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10m", + "capabilities:ed18cbc69ec23491": "mdn_plus_10m", + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqdulKb9q6OnNsLWgRvCo2X", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - EUR NL", + lookup_key: "eur-nl-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:b6f5727337fefe8e": "mdn_plus_10y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10y", + "capabilities:ed18cbc69ec23491": "mdn_plus_10y", + "product:successActionButtonLabel": "Doorgaan naar MDN Plus", + "product:subtitle": "Een MDN Premium-service", + "product:details:1": "Paginameldingen", + "product:details:2": "Verzamelingen artikelen", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqdulKb9q6OnNsLnNtjAc1b", + }, + }, + "eur-pt": { + mdn_plus_5m: { + unit_amount: 500, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - EUR PT", + lookup_key: "eur-pt-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:b6f5727337fefe8e": "mdn_plus_5m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5m", + "capabilities:ed18cbc69ec23491": "mdn_plus_5m", + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + price_id: "price_1L2tOVKb9q6OnNsLKEZeiAUa", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - EUR PT", + lookup_key: "eur-pt-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:b6f5727337fefe8e": "mdn_plus_5y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5y", + "capabilities:ed18cbc69ec23491": "mdn_plus_5y", + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + price_id: "price_1L2tOVKb9q6OnNsLlL79fx7O", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - EUR PT", + lookup_key: "eur-pt-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:b6f5727337fefe8e": "mdn_plus_10m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10m", + "capabilities:ed18cbc69ec23491": "mdn_plus_10m", + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + price_id: "price_1L2tOWKb9q6OnNsLlvcFItux", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - EUR PT", + lookup_key: "eur-pt-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:b6f5727337fefe8e": "mdn_plus_10y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10y", + "capabilities:ed18cbc69ec23491": "mdn_plus_10y", + "product:successActionButtonLabel": "Um Serviço Premium MDN", + "product:subtitle": "Notificações de página", + "product:details:1": "Coleções de artigos", + "product:details:2": "Continuar para o MDN Plus", + "product:details:3": "MDN Offline", + }, + price_id: "price_1L2tOWKb9q6OnNsLeDlMYfzM", + }, + }, + "eur-sk": { + mdn_plus_5m: { + unit_amount: 500, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - EUR SK", + lookup_key: "eur-sk-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:b6f5727337fefe8e": "mdn_plus_5m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5m", + "capabilities:ed18cbc69ec23491": "mdn_plus_5m", + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + price_id: "price_1L2tOXKb9q6OnNsLgdMHi7aT", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - EUR SK", + lookup_key: "eur-sk-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:b6f5727337fefe8e": "mdn_plus_5y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5y", + "capabilities:ed18cbc69ec23491": "mdn_plus_5y", + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + price_id: "price_1L2tOXKb9q6OnNsLY1NOhF8J", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - EUR SK", + lookup_key: "eur-sk-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:b6f5727337fefe8e": "mdn_plus_10m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10m", + "capabilities:ed18cbc69ec23491": "mdn_plus_10m", + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + price_id: "price_1L2tOXKb9q6OnNsL0USQVLnk", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - EUR SK", + lookup_key: "eur-sk-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:b6f5727337fefe8e": "mdn_plus_10y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10y", + "capabilities:ed18cbc69ec23491": "mdn_plus_10y", + "product:successActionButtonLabel": "Služba MDN Premium", + "product:subtitle": "Upozornenia na stránke", + "product:details:1": "Zbierky článkov", + "product:details:2": "Pokračujte na MDN Plus", + "product:details:3": "MDN offline", + }, + price_id: "price_1L2tOYKb9q6OnNsLLN78izjz", + }, + }, + "eur-sl": { + mdn_plus_5m: { + unit_amount: 500, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - EUR SL", + lookup_key: "eur-sl-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:b6f5727337fefe8e": "mdn_plus_5m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5m", + "capabilities:ed18cbc69ec23491": "mdn_plus_5m", + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + price_id: "price_1L2tOYKb9q6OnNsL0FTDUmNL", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - EUR SL", + lookup_key: "eur-sl-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:b6f5727337fefe8e": "mdn_plus_5y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5y", + "capabilities:ed18cbc69ec23491": "mdn_plus_5y", + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + price_id: "price_1L2tOZKb9q6OnNsLVUOKdstR", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - EUR SL", + lookup_key: "eur-sl-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:b6f5727337fefe8e": "mdn_plus_10m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10m", + "capabilities:ed18cbc69ec23491": "mdn_plus_10m", + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + price_id: "price_1L2tOZKb9q6OnNsL73fEBYE0", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - EUR SL", + lookup_key: "eur-sl-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:b6f5727337fefe8e": "mdn_plus_10y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10y", + "capabilities:ed18cbc69ec23491": "mdn_plus_10y", + "product:successActionButtonLabel": "Storitev MDN Premium", + "product:subtitle": "Obvestila strani", + "product:details:1": "Zbirke člankov", + "product:details:2": "Nadaljuj na MDN Plus", + "product:details:3": "MDN brez povezave", + }, + price_id: "price_1L2tOaKb9q6OnNsLroZYuVLp", + }, + }, + "eur-tr": { + mdn_plus_5m: { + unit_amount: 500, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - EUR TR", + lookup_key: "eur-tr-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:b6f5727337fefe8e": "mdn_plus_5m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5m", + "capabilities:ed18cbc69ec23491": "mdn_plus_5m", + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + price_id: "price_1L2tOaKb9q6OnNsLawGUUtNl", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - EUR TR", + lookup_key: "eur-tr-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:b6f5727337fefe8e": "mdn_plus_5y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5y", + "capabilities:ed18cbc69ec23491": "mdn_plus_5y", + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + price_id: "price_1L2tOaKb9q6OnNsL3LhuZ3lY", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - EUR TR", + lookup_key: "eur-tr-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:b6f5727337fefe8e": "mdn_plus_10m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10m", + "capabilities:ed18cbc69ec23491": "mdn_plus_10m", + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + price_id: "price_1L2tObKb9q6OnNsLtuAwE66M", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "eur", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - EUR TR", + lookup_key: "eur-tr-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:b6f5727337fefe8e": "mdn_plus_10y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10y", + "capabilities:ed18cbc69ec23491": "mdn_plus_10y", + "product:successActionButtonLabel": "Bir MDN Premium Hizmeti", + "product:subtitle": "Sayfa bildirimleri", + "product:details:1": "Toplanmış makaleler", + "product:details:2": "MDN Plus'a devam edin", + "product:details:3": "MDN çevrim dışı", + }, + price_id: "price_1L2tObKb9q6OnNsLdE48ccAa", + }, + }, + "chf-en": { + mdn_plus_5m: { + unit_amount: 500, + currency: "chf", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - CHF EN", + lookup_key: "chf-en-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:b6f5727337fefe8e": "mdn_plus_5m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5m", + "capabilities:ed18cbc69ec23491": "mdn_plus_5m", + "product:successActionButtonLabel": "Continue to MDN Plus", + "product:subtitle": "An MDN Premium Service", + "product:details:1": "Page notifications", + "product:details:2": "Collections of articles", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqdulKb9q6OnNsLbkK1T4dR", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "chf", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - CHF EN", + lookup_key: "chf-en-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:b6f5727337fefe8e": "mdn_plus_5y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5y", + "capabilities:ed18cbc69ec23491": "mdn_plus_5y", + "product:successActionButtonLabel": "Continue to MDN Plus", + "product:subtitle": "An MDN Premium Service", + "product:details:1": "Page notifications", + "product:details:2": "Collections of articles", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqdumKb9q6OnNsLfjFLaTzi", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "chf", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - CHF EN", + lookup_key: "chf-en-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:b6f5727337fefe8e": "mdn_plus_10m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10m", + "capabilities:ed18cbc69ec23491": "mdn_plus_10m", + "product:successActionButtonLabel": "Continue to MDN Plus", + "product:subtitle": "An MDN Premium Service", + "product:details:1": "Page notifications", + "product:details:2": "Collections of articles", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqdumKb9q6OnNsLc248nWtE", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "chf", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - CHF EN", + lookup_key: "chf-en-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:b6f5727337fefe8e": "mdn_plus_10y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10y", + "capabilities:ed18cbc69ec23491": "mdn_plus_10y", + "product:successActionButtonLabel": "Continue to MDN Plus", + "product:subtitle": "An MDN Premium Service", + "product:details:1": "Page notifications", + "product:details:2": "Collections of articles", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqdumKb9q6OnNsLEbRL4nAo", + }, + }, + "chf-de": { + mdn_plus_5m: { + unit_amount: 500, + currency: "chf", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - CHF DE", + lookup_key: "chf-de-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:b6f5727337fefe8e": "mdn_plus_5m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5m", + "capabilities:ed18cbc69ec23491": "mdn_plus_5m", + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqdunKb9q6OnNsLMgnnIma0", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "chf", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - CHF DE", + lookup_key: "chf-de-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:b6f5727337fefe8e": "mdn_plus_5y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5y", + "capabilities:ed18cbc69ec23491": "mdn_plus_5y", + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqdunKb9q6OnNsLiF9qvEVf", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "chf", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - CHF DE", + lookup_key: "chf-de-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:b6f5727337fefe8e": "mdn_plus_10m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10m", + "capabilities:ed18cbc69ec23491": "mdn_plus_10m", + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:details:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqdunKb9q6OnNsLnaEHicOP", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "chf", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - CHF DE", + lookup_key: "chf-de-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:b6f5727337fefe8e": "mdn_plus_10y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10y", + "capabilities:ed18cbc69ec23491": "mdn_plus_10y", + "product:successActionButtonLabel": "Weiter zu MDN Plus", + "product:subtitle": "Ein MDN-Premium-Dienst", + "product:details:1": "Seitenbenachrichtigungen", + "product:de;tails:2": "Artikelsammlung", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqduoKb9q6OnNsLQrxviGu0", + }, + }, + "chf-fr": { + mdn_plus_5m: { + unit_amount: 500, + currency: "chf", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - CHF FR", + lookup_key: "chf-fr-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:b6f5727337fefe8e": "mdn_plus_5m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5m", + "capabilities:ed18cbc69ec23491": "mdn_plus_5m", + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + price_id: "price_1KqduoKb9q6OnNsLv4AoSQJg", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "chf", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - CHF FR", + lookup_key: "chf-fr-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:b6f5727337fefe8e": "mdn_plus_5y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5y", + "capabilities:ed18cbc69ec23491": "mdn_plus_5y", + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + price_id: "price_1KqduoKb9q6OnNsLf9iSMYIf", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "chf", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - CHF FR", + lookup_key: "chf-fr-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:b6f5727337fefe8e": "mdn_plus_10m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10m", + "capabilities:ed18cbc69ec23491": "mdn_plus_10m", + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + price_id: "price_1KqdupKb9q6OnNsLWiJvcYUp", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "chf", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - CHF FR", + lookup_key: "chf-fr-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:b6f5727337fefe8e": "mdn_plus_10y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10y", + "capabilities:ed18cbc69ec23491": "mdn_plus_10y", + "product:successActionButtonLabel": "Continuer vers MDN Plus", + "product:subtitle": "Un service MDN Premium", + "product:details:1": "Notifications de la page", + "product:details:2": "Collections d’articles", + "product:details:3": "MDN hors ligne", + }, + price_id: "price_1KqdupKb9q6OnNsLcVJfbhL9", + }, + }, + "chf-it": { + mdn_plus_5m: { + unit_amount: 500, + currency: "chf", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 5m - CHF IT", + lookup_key: "chf-it-5m", + metadata: { + productSet: "mdnPlus", + productOrder: "1", + "capabilities:b6f5727337fefe8e": "mdn_plus_5m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5m", + "capabilities:ed18cbc69ec23491": "mdn_plus_5m", + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqdupKb9q6OnNsL1TqMroUf", + }, + mdn_plus_5y: { + unit_amount: 5000, + currency: "chf", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 5y - CHF IT", + lookup_key: "chf-it-5y", + metadata: { + productSet: "mdnPlus", + productOrder: "2", + "capabilities:b6f5727337fefe8e": "mdn_plus_5y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_5y", + "capabilities:ed18cbc69ec23491": "mdn_plus_5y", + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqduqKb9q6OnNsLhNwOl77S", + }, + mdn_plus_10m: { + unit_amount: 1000, + currency: "chf", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "month", + }, + nickname: "MDN Plus 10m - CHF IT", + lookup_key: "chf-it-10m", + metadata: { + productSet: "mdnPlus", + productOrder: "3", + "capabilities:b6f5727337fefe8e": "mdn_plus_10m", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10m", + "capabilities:ed18cbc69ec23491": "mdn_plus_10m", + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqduqKb9q6OnNsLZ9yMm4To", + }, + mdn_plus_10y: { + unit_amount: 10000, + currency: "chf", + product: "prod_Jtbg9tyGyLRuB0", + recurring: { + interval: "year", + }, + nickname: "MDN Plus 10y - CHF IT", + lookup_key: "chf-it-10y", + metadata: { + productSet: "mdnPlus", + productOrder: "4", + "capabilities:b6f5727337fefe8e": "mdn_plus_10y", + "capabilities:e7bc284c2d3b4a90": "mdn_plus_10y", + "capabilities:ed18cbc69ec23491": "mdn_plus_10y", + "product:successActionButtonLabel": "Prosegui su MDN Plus", + "product:subtitle": "Un servizio Premium MDN", + "product:details:1": "Notifiche delle pagine", + "product:details:2": "Raccolte di articoli", + "product:details:3": "MDN offline", + }, + price_id: "price_1KqdurKb9q6OnNsLUOz4fnk3", + }, + }, + }, +}; + +export default plans; diff --git a/cloud-function/src/utils.ts b/cloud-function/src/utils.ts new file mode 100644 index 000000000000..2e0cf39e608f --- /dev/null +++ b/cloud-function/src/utils.ts @@ -0,0 +1,44 @@ +import { Request, Response } from "express"; + +import { DEFAULT_COUNTRY } from "./constants.js"; + +export function getRequestCountry(req: Request): string { + const value = req.headers["cloudfront-viewer-country"]; + + if (typeof value === "string" && value !== "ZZ") { + return value; + } else { + return DEFAULT_COUNTRY; + } +} + +export function redirect( + res: Response, + location: string, + { status = 302, cacheControlSeconds = 0 } = {} +): void { + let cacheControlValue; + if (cacheControlSeconds) { + cacheControlValue = `max-age=${cacheControlSeconds},public`; + } else { + cacheControlValue = "no-store"; + } + + // We need to URL encode the pathname, but leave the query string as is. + // Suppose the old URL was `/search?q=text%2Dshadow` and all we need to do + // is to inject the locale to that URL, we should not URL encode the whole + // new URL otherwise you'd end up with `/en-US/search?q=text%252Dshadow` + // since the already encoded `%2D` would become `%252D` which is wrong and + // different. + const [pathname, querystring] = location.split("?", 2); + let newLocation = encodeURI(pathname || ""); + if (querystring) { + newLocation += `?${querystring}`; + } + + res.set("Cache-Control", cacheControlValue).redirect(status, newLocation); +} + +export function isLiveSampleURL(url: string) { + return url.includes("/_sample_."); +} diff --git a/cloud-function/tsconfig.json b/cloud-function/tsconfig.json new file mode 100644 index 000000000000..fae5d6bfe79b --- /dev/null +++ b/cloud-function/tsconfig.json @@ -0,0 +1,30 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "display": "Node 18 + ESM + Strictest", + "compilerOptions": { + "lib": ["es2022", "DOM"], + "module": "es2022", + "target": "es2022", + "strict": true, + "esModuleInterop": false, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "moduleResolution": "nodenext", + "allowUnusedLabels": false, + "allowUnreachableCode": false, + "exactOptionalPropertyTypes": true, + "noFallthroughCasesInSwitch": true, + "noImplicitOverride": true, + "noImplicitReturns": true, + "noPropertyAccessFromIndexSignature": true, + "noUncheckedIndexedAccess": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "checkJs": true + }, + "ts-node": { + "esm": true, + "swc": true + }, + "exclude": ["src/internal/*"] +} diff --git a/libs/locale-utils/index.js b/libs/locale-utils/index.js index 52f6b8168059..ec2e53780259 100644 --- a/libs/locale-utils/index.js +++ b/libs/locale-utils/index.js @@ -12,13 +12,25 @@ const VALID_LOCALES_LIST = [...VALID_LOCALES.values()]; // From https://github.com/aws-samples/cloudfront-authorization-at-edge/blob/01c1bc843d478977005bde86f5834ce76c479eec/src/lambda-edge/shared/shared.ts#L216 // but rewritten in JavaScript (from TypeScript). function extractCookiesFromHeaders(headers) { + let value = headers["cookie"]; + // Cookies are present in the HTTP header "Cookie" that may be present multiple times. // This utility function parses occurrences of that header and splits out all the cookies and their values // A simple object is returned that allows easy access by cookie name: e.g. cookies["nonce"] - if (!headers["cookie"]) { + if (!value) { return {}; } - const cookies = headers["cookie"].reduce( + + if (typeof value === "string") { + // Express. + value = [ + { + value, + }, + ]; + } + + const cookies = value.reduce( (reduced, header) => Object.assign(reduced, parse(header.value)), {} ); @@ -26,13 +38,25 @@ function extractCookiesFromHeaders(headers) { return cookies; } -function getCookie(headers, cookieKey) { - return extractCookiesFromHeaders(headers)[cookieKey]; +function getCookie(request, cookieKey) { + return extractCookiesFromHeaders(request.headers)[cookieKey]; +} + +function getAcceptLanguage(request) { + const acceptLangHeaders = request.headers["accept-language"]; + + if (typeof acceptLangHeaders === "string") { + // Express. + return acceptLangHeaders; + } + + const { value = null } = (acceptLangHeaders && acceptLangHeaders[0]) || {}; + return value; } export function getLocale(request, fallback = DEFAULT_LOCALE) { // First try by cookie. - const cookieLocale = getCookie(request.headers, PREFERRED_LOCALE_COOKIE_NAME); + const cookieLocale = getCookie(request, PREFERRED_LOCALE_COOKIE_NAME); if (cookieLocale) { // If it's valid, stick to it. if (VALID_LOCALES.has(cookieLocale.toLowerCase())) { @@ -41,8 +65,7 @@ export function getLocale(request, fallback = DEFAULT_LOCALE) { } // Each header in request.headers is always a list of objects. - const acceptLangHeaders = request.headers["accept-language"]; - const { value = null } = (acceptLangHeaders && acceptLangHeaders[0]) || {}; + const value = getAcceptLanguage(request); const locale = value && acceptLanguageParser.pick(VALID_LOCALES_LIST, value, { loose: true }); diff --git a/libs/locale-utils/package.json b/libs/locale-utils/package.json index 2fa2fb0d4057..8540243c4e0c 100644 --- a/libs/locale-utils/package.json +++ b/libs/locale-utils/package.json @@ -6,5 +6,9 @@ "type": "module", "exports": "./index.js", "main": "index.js", - "types": "index.d.ts" + "types": "index.d.ts", + "dependencies": { + "accept-language-parser": "^1.5.0", + "cookie": "^0.5.0" + } } diff --git a/libs/locale-utils/yarn.lock b/libs/locale-utils/yarn.lock new file mode 100644 index 000000000000..0c19b72a365e --- /dev/null +++ b/libs/locale-utils/yarn.lock @@ -0,0 +1,13 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +accept-language-parser@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/accept-language-parser/-/accept-language-parser-1.5.0.tgz#8877c54040a8dcb59e0a07d9c1fde42298334791" + integrity sha512-QhyTbMLYo0BBGg1aWbeMG4ekWtds/31BrEU+DONOg/7ax23vxpL03Pb7/zBmha2v7vdD3AyzZVWBVGEZxKOXWw== + +cookie@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" + integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== diff --git a/package.json b/package.json index eea13c8e1f98..b4b9a69aafd4 100644 --- a/package.json +++ b/package.json @@ -27,10 +27,11 @@ "eslint": "eslint .", "filecheck": "ts-node filecheck/cli.ts", "install:all": "find . -mindepth 2 -name 'yarn.lock' ! -wholename '**/node_modules/**' -print0 | xargs -n1 -0 sh -cx 'yarn --cwd $(dirname $0) install'", + "install:all:npm": "find . -mindepth 2 -name 'package-lock.json' ! -wholename '**/node_modules/**' -print0 | xargs -n1 -0 sh -cx 'npm --prefix $(dirname $0) install'", "jest": "cross-env NODE_OPTIONS=--experimental-vm-modules jest", "m2h": "ts-node markdown/m2h/cli.ts", "prepack": "yarn build:dist", - "prepare": "husky install && yarn install:all", + "prepare": "husky install && yarn install:all && yarn install:all:npm", "prettier-check": "prettier --check .", "prettier-format": "prettier --write .", "start": "(test -f client/build/index.html || yarn build:client) && (test -f ssr/dist/main.js || yarn build:ssr) && (test -d client/build/en-us/_spas || yarn tool spas) && nf -j Procfile.start start",