diff --git a/.github/workflows/ingest-pull.yml b/.github/workflows/ingest-pull.yml index 491c046c..37b59bb3 100644 --- a/.github/workflows/ingest-pull.yml +++ b/.github/workflows/ingest-pull.yml @@ -1,4 +1,3 @@ - name: ingest pull on: @@ -7,7 +6,6 @@ on: env: NODE_VERSION: 18 - jobs: security: @@ -15,8 +13,8 @@ jobs: runs-on: ubuntu-latest if: contains(github.event.pull_request.labels.*.name, 'safe to test') steps: - - run: | - echo "Security checks passed!" + - run: | + echo "Security checks passed!" test: needs: security @@ -25,56 +23,56 @@ jobs: matrix: STAGES: [dev] steps: - - name: πŸ‘€ Checkout Code - uses: actions/checkout@v3 + - name: πŸ‘€ Checkout Code + uses: actions/checkout@v3 - - name: ⛺️ Install Node.js - uses: actions/setup-node@v3 - with: - node-version: ${{ env.NODE_VERSION }} - cache: 'yarn' - cache-dependency-path: '**/yarn.lock' + - name: ⛺️ Install Node.js + uses: actions/setup-node@v3 + with: + node-version: ${{ env.NODE_VERSION }} + cache: "yarn" + cache-dependency-path: "**/yarn.lock" - - name: πŸ“¦ Install Dependencies - run: yarn + - name: πŸ“¦ Install Dependencies + run: yarn - - name: πŸ”‘ Setup Google Cloud Auth - uses: google-github-actions/setup-gcloud@v0 - with: - service_account_key: ${{ secrets.GCP_GITHUB_SERVICE_ACCOUNT_KEY }} - export_default_credentials: true + - name: πŸ”‘ Setup Google Cloud Auth + uses: google-github-actions/setup-gcloud@v0 + with: + service_account_key: ${{ secrets.GCP_GITHUB_SERVICE_ACCOUNT_KEY }} + export_default_credentials: true - - name: πŸ“š Lint Code - run: yarn ingest:lint + - name: πŸ“š Lint Code + run: yarn ingest:lint - - name: πŸ§ͺ Run Ingest Tests - env: - SERVICE_NAME: ard-eventhub - STAGE: ${{ matrix.STAGES }} - DD_TRACE_ENABLED: false - GCP_PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }} - FIREBASE_API_KEY: ${{ secrets.TEST_FIREBASE_API_KEY }} - TEST_USER: ${{ secrets.TEST_USER }} - TEST_USER_PW: ${{ secrets.TEST_USER_PW }} - PUBSUB_SERVICE_ACCOUNT_EMAIL_INTERNAL: ${{ secrets.PUBSUB_SERVICE_ACCOUNT_EMAIL }} - run: yarn ingest:test + - name: πŸ§ͺ Run Ingest Tests + env: + SERVICE_NAME: ard-eventhub + STAGE: ${{ matrix.STAGES }} + DD_TRACE_ENABLED: false + GCP_PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }} + FIREBASE_API_KEY: ${{ secrets.TEST_FIREBASE_API_KEY }} + TEST_USER: ${{ secrets.TEST_USER }} + TEST_USER_PW: ${{ secrets.TEST_USER_PW }} + PUBSUB_SERVICE_ACCOUNT_EMAIL_INTERNAL: ${{ secrets.PUBSUB_SERVICE_ACCOUNT_EMAIL }} + run: yarn ingest:test license: needs: security runs-on: ubuntu-latest steps: - - name: πŸ‘€ Checkout Code - uses: actions/checkout@v3 + - name: πŸ‘€ Checkout Code + uses: actions/checkout@v3 - - name: ⛺️ Install Node.js - uses: actions/setup-node@v3 - with: - node-version: ${{ env.NODE_VERSION }} - cache: 'yarn' - cache-dependency-path: '**/yarn.lock' + - name: ⛺️ Install Node.js + uses: actions/setup-node@v3 + with: + node-version: ${{ env.NODE_VERSION }} + cache: "yarn" + cache-dependency-path: "**/yarn.lock" - - name: πŸ“¦ Install Dependencies - run: yarn + - name: πŸ“¦ Install Dependencies + run: yarn - - name: πŸ“š Run License Check - run: yarn license + - name: πŸ“š Run License Check + run: yarn license diff --git a/.github/workflows/ingest-push.yml b/.github/workflows/ingest-push.yml index 7791e534..7cbb062c 100644 --- a/.github/workflows/ingest-push.yml +++ b/.github/workflows/ingest-push.yml @@ -1,13 +1,12 @@ - name: ingest push on: push: branches: - - feature/* - - dev/* + - feature/* + - dev/* pull_request: - types: [ closed ] + types: [closed] env: NODE_VERSION: 18 @@ -20,8 +19,8 @@ jobs: runs-on: ubuntu-latest if: "github.event.pull_request.merged == true || github.event_name == 'push'" steps: - - run: | - echo "Security checks passed!" + - run: | + echo "Security checks passed!" test: needs: security @@ -30,39 +29,39 @@ jobs: matrix: STAGES: [dev] steps: - - name: πŸ‘€ Checkout Code - uses: actions/checkout@v3 - - - name: ⛺️ Install Node.js - uses: actions/setup-node@v3 - with: - node-version: ${{ env.NODE_VERSION }} - cache: 'yarn' - cache-dependency-path: '**/yarn.lock' - - - name: πŸ“¦ Install Dependencies - run: yarn - - - name: πŸ”‘ Setup Google Cloud Auth - uses: google-github-actions/setup-gcloud@v0 - with: - service_account_key: ${{ secrets.GCP_GITHUB_SERVICE_ACCOUNT_KEY }} - export_default_credentials: true - - - name: πŸ“š Lint Code - run: yarn ingest:lint - - - name: πŸ§ͺ Run Ingest Tests - env: - SERVICE_NAME: ard-eventhub - STAGE: ${{ matrix.STAGES }} - DD_TRACE_ENABLED: false - GCP_PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }} - FIREBASE_API_KEY: ${{ secrets.TEST_FIREBASE_API_KEY }} - TEST_USER: ${{ secrets.TEST_USER }} - TEST_USER_PW: ${{ secrets.TEST_USER_PW }} - PUBSUB_SERVICE_ACCOUNT_EMAIL_INTERNAL: ${{ secrets.PUBSUB_SERVICE_ACCOUNT_EMAIL }} - run: yarn ingest:test + - name: πŸ‘€ Checkout Code + uses: actions/checkout@v3 + + - name: ⛺️ Install Node.js + uses: actions/setup-node@v3 + with: + node-version: ${{ env.NODE_VERSION }} + cache: "yarn" + cache-dependency-path: "**/yarn.lock" + + - name: πŸ“¦ Install Dependencies + run: yarn + + - name: πŸ”‘ Setup Google Cloud Auth + uses: google-github-actions/setup-gcloud@v0 + with: + service_account_key: ${{ secrets.GCP_GITHUB_SERVICE_ACCOUNT_KEY }} + export_default_credentials: true + + - name: πŸ“š Lint Code + run: yarn ingest:lint + + - name: πŸ§ͺ Run Ingest Tests + env: + SERVICE_NAME: ard-eventhub + STAGE: ${{ matrix.STAGES }} + DD_TRACE_ENABLED: false + GCP_PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }} + FIREBASE_API_KEY: ${{ secrets.TEST_FIREBASE_API_KEY }} + TEST_USER: ${{ secrets.TEST_USER }} + TEST_USER_PW: ${{ secrets.TEST_USER_PW }} + PUBSUB_SERVICE_ACCOUNT_EMAIL_INTERNAL: ${{ secrets.PUBSUB_SERVICE_ACCOUNT_EMAIL }} + run: yarn ingest:test docker: runs-on: ubuntu-latest @@ -71,72 +70,72 @@ jobs: BRANCH: ${{ steps.push.outputs.BRANCH }} VERSION: ${{ steps.push.outputs.VERSION }} steps: - - name: πŸ‘€ Checkout Code - uses: actions/checkout@v3 - - - name: πŸ”‘ Setup Google Cloud Auth - uses: google-github-actions/setup-gcloud@v0 - with: - service_account_key: ${{ secrets.GCP_GITHUB_SERVICE_ACCOUNT_KEY }} - export_default_credentials: true - - - name: πŸ”‘ Login to Registry - run: "gcloud auth configure-docker $REGISTRY_DOMAIN" - - - name: 🚧 Building docker image - run: "docker build ./ --file ./Dockerfile -t image" - - - name: πŸ”– Get Package Version - id: package-version - uses: martinbeentjes/npm-get-version-action@main - - - name: 🏷 Tagging & Pushing docker - id: push - run: | - # Strip git ref prefix from version - BRANCH=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,') - - # Strip "v" prefix from tag name - [[ "${{ github.ref }}" == "refs/tags/"* ]] && BRANCH=$(echo $BRANCH | sed -e 's/^v//') - - # Add custom wrapper syntax - VERSION=${{ steps.package-version.outputs.current-version }}-g${{ github.run_number }} - - # Set registry - IMAGE_URI=$REGISTRY_DOMAIN/${{ secrets.GCP_PROJECT_ID }}/$IMAGE_NAME:$VERSION - - # Push image to registry - docker tag image $IMAGE_URI - docker push $IMAGE_URI - - # Update vars - echo "::set-output name=BRANCH::$BRANCH" - echo "::set-output name=VERSION::$VERSION" - - # Print vars - echo "::warning docker::BRANCH $BRANCH" - echo "::warning docker::VERSION $VERSION" - - - name: πŸ’¬ Comment Branch and Version - uses: peter-evans/create-or-update-comment@v2 - if: github.event.pull_request.merged == true - with: - issue-number: ${{ github.event.pull_request.number }} - body: | - Docker container is ready! - - BRANCH: - ``` - ${{ steps.push.outputs.BRANCH }} - ``` - - VERSION: - ``` - ${{ steps.push.outputs.VERSION }} - ``` - - - name: πŸ‘‹ Logout - run: "docker logout" + - name: πŸ‘€ Checkout Code + uses: actions/checkout@v3 + + - name: πŸ”‘ Setup Google Cloud Auth + uses: google-github-actions/setup-gcloud@v0 + with: + service_account_key: ${{ secrets.GCP_GITHUB_SERVICE_ACCOUNT_KEY }} + export_default_credentials: true + + - name: πŸ”‘ Login to Registry + run: "gcloud auth configure-docker $REGISTRY_DOMAIN" + + - name: 🚧 Building docker image + run: "docker build ./ --file ./Dockerfile -t image" + + - name: πŸ”– Get Package Version + id: package-version + uses: martinbeentjes/npm-get-version-action@main + + - name: 🏷 Tagging & Pushing docker + id: push + run: | + # Strip git ref prefix from version + BRANCH=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,') + + # Strip "v" prefix from tag name + [[ "${{ github.ref }}" == "refs/tags/"* ]] && BRANCH=$(echo $BRANCH | sed -e 's/^v//') + + # Add custom wrapper syntax + VERSION=${{ steps.package-version.outputs.current-version }}-g${{ github.run_number }} + + # Set registry + IMAGE_URI=$REGISTRY_DOMAIN/${{ secrets.GCP_PROJECT_ID }}/$IMAGE_NAME:$VERSION + + # Push image to registry + docker tag image $IMAGE_URI + docker push $IMAGE_URI + + # Update vars + echo "::set-output name=BRANCH::$BRANCH" + echo "::set-output name=VERSION::$VERSION" + + # Print vars + echo "::warning docker::BRANCH $BRANCH" + echo "::warning docker::VERSION $VERSION" + + - name: πŸ’¬ Comment Branch and Version + uses: peter-evans/create-or-update-comment@v2 + if: github.event.pull_request.merged == true + with: + issue-number: ${{ github.event.pull_request.number }} + body: | + Docker container is ready! + + BRANCH: + ``` + ${{ steps.push.outputs.BRANCH }} + ``` + + VERSION: + ``` + ${{ steps.push.outputs.VERSION }} + ``` + + - name: πŸ‘‹ Logout + run: "docker logout" deploy-A-dev-kubernetes: if: github.event.pull_request.merged == true @@ -144,14 +143,14 @@ jobs: needs: docker runs-on: ubuntu-latest steps: - - name: πŸš€ Trigger deployment to dev - run: | - curl --location --request POST '${{ secrets.ARD_DEPLOYMENT_HOST }}' \ - -s -w "%{http_code}\n" \ - --header 'Authorization: Basic ${{ secrets.ARD_DEPLOYMENT_TOKEN }}' \ - --form 'UMGEBUNG="dev"' \ - --form 'COMPONENT="eventhub-ingest"' \ - --form 'VERSION="${{ needs.docker.outputs.VERSION }}"' + - name: πŸš€ Trigger deployment to dev + run: | + curl --location --request POST '${{ secrets.ARD_DEPLOYMENT_HOST }}' \ + -s -w "%{http_code}\n" \ + --header 'Authorization: Basic ${{ secrets.ARD_DEPLOYMENT_TOKEN }}' \ + --form 'UMGEBUNG="dev"' \ + --form 'COMPONENT="eventhub-ingest"' \ + --form 'VERSION="${{ needs.docker.outputs.VERSION }}"' deploy-B-test-kubernetes: if: github.event.pull_request.merged == true @@ -159,14 +158,14 @@ jobs: needs: docker runs-on: ubuntu-latest steps: - - name: πŸš€ Trigger deployment to test - run: | - curl --location --request POST '${{ secrets.ARD_DEPLOYMENT_HOST }}' \ - -s -w "%{http_code}\n" \ - --header 'Authorization: Basic ${{ secrets.ARD_DEPLOYMENT_TOKEN }}' \ - --form 'UMGEBUNG="test"' \ - --form 'COMPONENT="eventhub-ingest"' \ - --form 'VERSION="${{ needs.docker.outputs.VERSION }}"' + - name: πŸš€ Trigger deployment to test + run: | + curl --location --request POST '${{ secrets.ARD_DEPLOYMENT_HOST }}' \ + -s -w "%{http_code}\n" \ + --header 'Authorization: Basic ${{ secrets.ARD_DEPLOYMENT_TOKEN }}' \ + --form 'UMGEBUNG="test"' \ + --form 'COMPONENT="eventhub-ingest"' \ + --form 'VERSION="${{ needs.docker.outputs.VERSION }}"' deploy-C-beta-kubernetes: if: github.event.pull_request.merged == true @@ -174,11 +173,11 @@ jobs: needs: docker runs-on: ubuntu-latest steps: - - name: πŸš€ Trigger deployment to beta - run: | - curl --location --request POST '${{ secrets.ARD_DEPLOYMENT_HOST }}' \ - -s -w "%{http_code}\n" \ - --header 'Authorization: Basic ${{ secrets.ARD_DEPLOYMENT_TOKEN }}' \ - --form 'UMGEBUNG="beta"' \ - --form 'COMPONENT="eventhub-ingest"' \ - --form 'VERSION="${{ needs.docker.outputs.VERSION }}"' + - name: πŸš€ Trigger deployment to beta + run: | + curl --location --request POST '${{ secrets.ARD_DEPLOYMENT_HOST }}' \ + -s -w "%{http_code}\n" \ + --header 'Authorization: Basic ${{ secrets.ARD_DEPLOYMENT_TOKEN }}' \ + --form 'UMGEBUNG="beta"' \ + --form 'COMPONENT="eventhub-ingest"' \ + --form 'VERSION="${{ needs.docker.outputs.VERSION }}"' diff --git a/.license-compliancerc.js b/.license-compliancerc.js new file mode 100644 index 00000000..62a67499 --- /dev/null +++ b/.license-compliancerc.js @@ -0,0 +1,109 @@ +// +// ard-eventhub +// by SWR audio lab +// + +// This helper runs the license-compliance toolkit using +// a pre-defined list of allowed licenses +// +// To make it runnable on your system, +// you might need to execute this command first: +// chmod +x license.sh +// + +// +// --- EXCLUDE --- +// +// doctrine for undetected Apache-2.0 license (allowed) +// hdr-histogram-js for undetected BSD-2 license (allowed) +// spdx-exceptions due to CC license (excluded in README) +// + +// +// --- ALLOW --- +// +// The list of allowed licenses was copied from +// https://joinup.ec.europa.eu/collection/eupl/matrix-eupl-compatible-open-source-licences +// as of February 25th, 2021 +// +// 0BSD added since copy of ISC +// https://opensource.org/licenses/0BSD +// +// CC0-1.0 added as it looks compatible and credit to sources is given +// https://creativecommons.org/publicdomain/zero/1.0/ +// + +// +// --- RESULT --- +// +// If any of the direct dependencies used in this project is not compliant +// with the list of allowed licenses, the script will print them as a list. +// If all licenses are compliant, the script will exit silently. +// + +module.exports = { + allow: [ + 'AFL-3.0', + 'APL-1.0', + 'Apache-2.0', + 'APSL-2.0', + 'Artistic-2.0', + 'AAL', + 'BSL-1.0', + 'BSD-2-Clause', + 'BSD-3-Clause', + 'CATOSL-1.1', + 'CDDL-1.0', + 'CPAL-1.0', + 'CUA-OPL-1.0', + 'EPL-1.0', + 'ECL-2.0', + 'EFL-2.0', + 'Entessa', + 'EUDatagrid', + 'EUPL-1.1', + 'EUPL-1.2', + 'Fair', + 'Frameworx-1.0', + 'LGPL-2.1', + 'LGPL-3.0', + 'IPL-1.0', + 'ISC', + 'LPPL-1.3c', + 'LPL-1.02', + 'MS-PL', + 'MS-RL', + 'MirOS', + 'MIT', + 'Motosoto', + 'MPL-1.1', + 'Multics', + 'NASA-1.3', + 'NTP', + 'Naumen', + 'OFL-1.1', + 'OGTSL', + 'PHP-3.0', + 'PostgreSQL', + 'Python-2.0', + 'QPL-1.0', + 'RPSL-1.0', + 'RSCPL', + 'SimPL-2.0', + 'Sleepycat', + 'SPL-1.0', + 'Watcom-1.0', + 'NCSA', + 'VSL-1.0', + 'W3C', + 'Xnet', + 'ZPL-2.0', + 'Zlib', + '0BSD', + 'CC0-1.0', + ], + exclude: ['doctrine', 'hdr-histogram-js', 'spdx-exceptions'], + direct: true, + format: 'text', + report: 'summary', +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 11551149..f7bc9bad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,9 +5,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.3.8] - 2022-08-22 + +- chore: code-format and linting +- chore: update node-dependencies +- feat: license-compliance with js + ## [1.3.7] - 2022-07-25 -- chore: update Node to `v18` +- chore: update Node.js to `v18` - chore: update node-utils to `v1.0.0` - fix: resolve eslint errors - fix: reorder core-dump (alphabetically institutions) @@ -20,9 +26,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.3.5] - 2022-06-21 -- security: fix `CVE-2022-24434` -- security: fix `CVE-2022-32210` -- security: fix `CVE-2022-33987` - update: github-actions to use latest versions - update: @google-cloud/secret-manager to `v4.0.0` - update: @google-cloud/datastore to `v7.0.0` @@ -31,7 +34,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.3.4] - 2022-06-07 -- security: fix `CVE-2022-25878` - update: actions/setup-node to `v3.2.0` - update: @google-cloud/pubsub to `v3.0.1` @@ -43,7 +45,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.3.2] - 2022-05-03 -- chore: update Node to `v16.15` +- chore: update Node.js to `v16.15` - fix: require service-name - update: mocha to `v10.0.0` - update: /create-or-update-comment to `v2.0.0` @@ -51,26 +53,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.3.1] - 2022-04-26 - add: SR channels `UNSERDING` and `AntenneSaar` -- security: fix `CVE-2022-24785` - update: actions/checkout to `v3.0.2` - update: actions/setup-node to `v3.1.1` - update: actions/setup-gcloud to `v0.6.0` ## [1.3.0] - 2022-03-28 -- chore: update Node to `v16.14.2` +- chore: update Node.js to `v16.14.2` - chore: change name of `Dockerfile` - chore: update node-crc to `v2` - add: `rustup` to build process - fix: `setup-gcloud` default branch -- security: fix `CVE-2021-44906` ## [1.2.9] - 2022-03-17 - add: new deploy-process for prod - chore: remove `eslint-plugin-swr` - chore: update peer-dependencies -- security: fix `CVE-2022-24772` ## [1.2.8] - 2022-03-15 @@ -79,13 +78,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.2.7] - 2022-03-01 -- security: fix `CVE-2022-23647` - chore: update setup-node to `v3` - chore: update dependencies ## [1.2.6] - 2022-02-14 -- chore: update Node to `v16.14` +- chore: update Node.js to `v16.14` - chore: update dependencies - replace `undici-wrapper` with `@swrlab/utils` @@ -103,8 +101,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.2.3] - 2021-12-13 - Fix IDs of two MDR channels -- Fix for `GHSA-qrmm-w75w-3wpx` -- Update Node to `v16.13.1` +- Update Node.js to `v16.13.1` - Update project dependencies ## [1.2.2] - 2021-11-30 @@ -120,7 +117,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.2.0] - 2021-10-19 -- Update Node to [v16.11.1](https://nodejs.org/en/blog/vulnerability/oct-2021-security-releases/) +- Update Node.js to [v16.11.1](https://nodejs.org/en/blog/vulnerability/oct-2021-security-releases/) - Update project dependencies - Update to `python3` in docker - Swap `node-fetch` for `undici-wrapper` @@ -129,7 +126,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.1.5] - 2021-09-27 -- Fix for `SNYK-JS-ANSIREGEX-1583908` - Update project dependencies - Update github actions @@ -148,7 +144,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.1.1] - 2021-06-30 -- Fix for CVE-2021-32723 - Update project dependencies - Remove deprecated body-parser @@ -163,7 +158,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.0.1] - 2021-05-10 -- Fixes for CVE-2021-27515 and CVE-2021-23362 - Update project dependencies ## [1.0.0] - 2021-04-09 diff --git a/README.md b/README.md index 4988a2ec..3e5477ed 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ This source code is provided under EUPL v1.2, except for the [`spdx-exceptions`] | NPM | `uuid` | [MIT](https://github.com/uuidjs/uuid/blob/master/LICENSE.md) | | NPM | `winston` | [MIT](https://github.com/winstonjs/winston/blob/master/LICENSE) | | NPM DEV | `@swrlab/eslint-plugin-swr` | [ISC](https://github.com/swrlab/eslint-plugin-swr/blob/main/package.json) | -| NPM DEV | `@swrlab/swr-prettier-config` | [ISC](https://github.com/swrlab/prettier-config/blob/main/license.md) | +| NPM DEV | `@swrlab/swr-prettier-config` | [MIT](https://github.com/swrlab/swr-prettier-config/blob/main/LICENSE.txt) | | NPM DEV | `chai` | [MIT](https://github.com/chaijs/chai/blob/master/LICENSE) | | NPM DEV | `chai-http` | [MIT](https://github.com/chaijs/chai-http/blob/master/package.json) | | NPM DEV | `docsify-cli` | [MIT](https://github.com/docsifyjs/docsify-cli/blob/master/LICENSE) | diff --git a/license.sh b/license.sh deleted file mode 100755 index 4267f618..00000000 --- a/license.sh +++ /dev/null @@ -1,102 +0,0 @@ -# -# ard-eventhub -# by SWR audio lab -# -# This helper runs the license-compliance toolkit using -# a pre-defined list of allowed licencses -# -# To make it runnable on your system, -# you might need to execute this command first: -# chmod +x license.sh -# - -# -# --- EXCLUDE --- -# -# doctrine for undetected Apache-2.0 license (allowed) -# hdr-histogram-js for undetected BSD-2 license (allowed) -# spdx-exceptions due to CC license (excluded in README) -# - -# -# --- ALLOW --- -# -# The list of allowed licenses was copied from -# https://joinup.ec.europa.eu/collection/eupl/matrix-eupl-compatible-open-source-licences -# as of February 25th, 2021 -# -# 0BSD added since copy of ISC -# https://opensource.org/licenses/0BSD -# -# CC0-1.0 added as it looks compatible and credit to sources is given -# https://creativecommons.org/publicdomain/zero/1.0/ -# - -license-compliance \ - --report summary \ - -t \ - --exclude "\ - doctrine;\ - hdr-histogram-js;\ - spdx-exceptions\ - "\ - --allow "\ - AFL-3.0;\ - APL-1.0;\ - Apache-2.0;\ - APSL-2.0;\ - Artistic-2.0;\ - AAL;\ - BSL-1.0;\ - BSD-2-Clause;\ - BSD-3-Clause;\ - CATOSL-1.1;\ - CDDL-1.0;\ - CPAL-1.0;\ - CUA-OPL-1.0;\ - EPL-1.0;\ - ECL-2.0;\ - EFL-2.0;\ - Entessa;\ - EUDatagrid;\ - EUPL-1.1;\ - EUPL-1.2;\ - Fair;\ - Frameworx-1.0;\ - LGPL-2.1;\ - LGPL-3.0;\ - IPL-1.0;\ - ISC;\ - LPPL-1.3c;\ - LPL-1.02;\ - MS-PL;\ - MS-RL;\ - MirOS;\ - MIT;\ - Motosoto;\ - MPL-1.1;\ - Multics;\ - NASA-1.3;\ - NTP;\ - Naumen;\ - OFL-1.1;\ - OGTSL;\ - PHP-3.0;\ - PostgreSQL;\ - Python-2.0;\ - QPL-1.0;\ - RPSL-1.0;\ - RSCPL;\ - SimPL-2.0;\ - Sleepycat;\ - SPL-1.0;\ - Watcom-1.0;\ - NCSA;\ - VSL-1.0;\ - W3C;\ - Xnet;\ - ZPL-2.0;\ - Zlib;\ - 0BSD;\ - CC0-1.0\ - " diff --git a/openapi.json b/openapi.json index cab110b7..2c2d475a 100644 --- a/openapi.json +++ b/openapi.json @@ -1,1360 +1,1301 @@ { - "openapi": "3.0.3", - "info": { - "title": "ARD-Eventhub", - "description": "ARD system to distribute real-time (live) metadata for primarily radio broadcasts.", - "termsOfService": "https://www.ard.de", - "contact": { - "email": "lab@swr.de" - }, - "license": { - "name": "European Union Public License 1.2", - "url": "https://spdx.org/licenses/EUPL-1.2.html" - }, - "version": "1.3.7" - }, - "externalDocs": { - "description": "ARD-Eventhub Documentation", - "url": "https://swrlab.github.io/ard-eventhub/" - }, - "servers": [ - { - "url": "/", - "description": "Local (domain-relative) environment" - } - ], - "tags": [ - { - "name": "auth", - "description": "Authentication services for Eventhub" - }, - { - "name": "events", - "description": "Manage events" - }, - { - "name": "subscriptions", - "description": "Access to subscription management" - }, - { - "name": "topics", - "description": "Access to topics details" - } - ], - "paths": { - "/auth/login": { - "post": { - "tags": [ - "auth" - ], - "summary": "Swap login credentials for a token", - "operationId": "authLoginPost", - "requestBody": { - "content": { - "application/json": { - "schema": { - "additionalProperties": false, - "type": "object", - "properties": { - "email": { - "type": "string", - "example": "my-email@example.com" - }, - "password": { - "type": "string", - "example": "my-password" - } - } - } - } - } - }, - "responses": { - "200": { - "description": "Authentication successful", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/authResponse" - } - } - } - }, - "400": { - "description": "Bad Request (invalid input)", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/errorBadRequest" - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/errorInternalServerError" - } - } - } - } - } - } - }, - "/auth/refresh": { - "post": { - "tags": [ - "auth" - ], - "summary": "Swap refresh token for new id token", - "operationId": "authRefreshPost", - "requestBody": { - "content": { - "application/json": { - "schema": { - "additionalProperties": false, - "type": "object", - "properties": { - "refreshToken": { - "type": "string", - "example": "abcXYZ..." - } - } - } - } - } - }, - "responses": { - "200": { - "description": "Authentication successful", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/authResponse" - } - } - } - }, - "400": { - "description": "Bad Request (invalid input)", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/errorBadRequest" - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/errorInternalServerError" - } - } - } - } - } - } - }, - "/auth/reset": { - "post": { - "tags": [ - "auth" - ], - "summary": "Request password reset email", - "operationId": "authResetPost", - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "email": { - "type": "string", - "example": "my-email@example.com" - } - } - } - } - } - }, - "responses": { - "200": { - "description": "Request successful", - "content": {} - }, - "400": { - "description": "Bad Request (invalid input)", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/errorBadRequest" - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/errorInternalServerError" - } - } - } - } - } - } - }, - "/events/de.ard.eventhub.v1.radio.track.next": { - "post": { - "tags": [ - "events" - ], - "summary": "Distribute a next track", - "operationId": "eventPostV1RadioTrackNext", - "security": [ - { - "bearerAuth": [] - } - ], - "requestBody": { - "$ref": "#/components/requestBodies/eventV1RadioTrack" - }, - "responses": { - "201": { - "$ref": "#/components/responses/eventV1RadioTrack" - }, - "400": { - "description": "Bad Request (invalid input)", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/errorBadRequest" - } - } - } - }, - "401": { - "description": "Missing authentication", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/errorUnauthorized" - } - } - } - }, - "403": { - "description": "Invalid authorization", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/errorForbidden" - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/errorInternalServerError" - } - } - } - } - } - } - }, - "/events/de.ard.eventhub.v1.radio.track.playing": { - "post": { - "tags": [ - "events" - ], - "summary": "Distribute a now-playing track", - "operationId": "eventPostV1RadioTrackPlaying", - "security": [ - { - "bearerAuth": [] - } - ], - "requestBody": { - "$ref": "#/components/requestBodies/eventV1RadioTrack" - }, - "responses": { - "201": { - "$ref": "#/components/responses/eventV1RadioTrack" - }, - "400": { - "description": "Bad Request (invalid input)", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/errorBadRequest" - } - } - } - }, - "401": { - "description": "Missing authentication", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/errorUnauthorized" - } - } - } - }, - "403": { - "description": "Invalid authorization", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/errorForbidden" - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/errorInternalServerError" - } - } - } - } - } - } - }, - "/subscriptions": { - "get": { - "tags": [ - "subscriptions" - ], - "summary": "List all subscriptions for this user", - "operationId": "subscriptionList", - "security": [ - { - "bearerAuth": [] - } - ], - "responses": { - "200": { - "description": "Subscriptions found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/subscriptionsList" - } - } - } - }, - "401": { - "description": "Missing authentication", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/errorUnauthorized" - } - } - } - }, - "403": { - "description": "Invalid authorization", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/errorForbidden" - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/errorInternalServerError" - } - } - } - } - } - }, - "post": { - "tags": [ - "subscriptions" - ], - "summary": "Add a new subscription", - "operationId": "subscriptionPost", - "security": [ - { - "bearerAuth": [] - } - ], - "requestBody": { - "description": "New event to be distributed to subscribers.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/subscriptionPost" - } - } - }, - "required": true - }, - "responses": { - "201": { - "description": "Subscription created", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/subscriptionResponse" - } - } - } - }, - "400": { - "description": "Bad Request (invalid input)", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/errorBadRequest" - } - } - } - }, - "401": { - "description": "Missing authentication", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/errorUnauthorized" - } - } - } - }, - "403": { - "description": "Invalid authorization", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/errorForbidden" - } - } - } - }, - "404": { - "description": "Topic for subscription not found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/errorNotFound" - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/errorInternalServerError" - } - } - } - } - } - } - }, - "/subscriptions/{name}": { - "get": { - "tags": [ - "subscriptions" - ], - "summary": "Get details about a single subscription from this user", - "operationId": "subscriptionsGet", - "security": [ - { - "bearerAuth": [] - } - ], - "parameters": [ - { - "name": "name", - "in": "path", - "description": "`name` of the desired subscription", - "required": true, - "style": "simple", - "explode": false, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Subscription found", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/subscriptionResponse" - } - } - } - } - }, - "401": { - "description": "Missing authentication", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/errorUnauthorized" - } - } - } - }, - "403": { - "description": "Invalid authorization", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/errorForbidden" - } - } - } - }, - "404": { - "description": "Subscription not found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/errorNotFound" - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/errorInternalServerError" - } - } - } - } - } - }, - "delete": { - "tags": [ - "subscriptions" - ], - "summary": "Remove a single subscription by this user", - "operationId": "subscriptionsDelete", - "security": [ - { - "bearerAuth": [] - } - ], - "parameters": [ - { - "name": "name", - "in": "path", - "description": "`name` of the desired subscription", - "required": true, - "style": "simple", - "explode": false, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Subscription deleted", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/subscriptionDeleted" - } - } - } - }, - "401": { - "description": "Missing authentication", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/errorUnauthorized" - } - } - } - }, - "403": { - "description": "Invalid authorization", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/errorForbidden" - } - } - } - }, - "404": { - "description": "Subscription not found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/errorNotFound" - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/errorInternalServerError" - } - } - } - } - } - } - }, - "/topics": { - "get": { - "tags": [ - "topics" - ], - "summary": "List all available topics", - "operationId": "topicsGet", - "security": [ - { - "bearerAuth": [] - } - ], - "responses": { - "200": { - "description": "Topics found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/topicResponse" - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/errorInternalServerError" - } - } - } - } - } - } - } - }, - "components": { - "requestBodies": { - "eventV1RadioTrack": { - "description": "New event to be distributed to subscribers. \n \nThe Eventhub format validation expects only a subset of these variables as minimum set. All other fields are technically optional, but **highly encouraged** to be included, so a best-possible metadata exchange is possible. \nThe subset is defined in the list of required fields of Schemas `eventV1PostBody`, resulting in this body: \n```json\n{\n \"type\": \"music\",\n \"start\": \"2020-01-19T06:00:00+01:00\",\n \"title\": \"Song name\",\n \"services\": [ { ... } ],\n \"playlistItemId\": \"swr3-5678\"\n}\n```\nRequired fields not specified in the Schema, will cause your request to fail. \n \nThe `id` is inserted by Eventhub as string-formatted number, but might be a true string in the future, do not expect this string to remain numbers only!\n", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/eventV1PostBody" - } - } - }, - "required": true - } - }, - "responses": { - "eventV1RadioTrack": { - "description": "Event created \n \n*Note:* The first request of an event for an externalId that is not registered yet, will return the status `failed: 1`. This indicates that a new topic for the externalId has been created, and the request needs to be repeated:\n```json\n\"statuses\": {\n \"published\": 0,\n \"blocked\": 0,\n \"failed\": 1\n}\n```\nIf the request returns the status `blocked: 1`, it indicates that you are not allowed to publish events under the given publisherId.\n", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/eventV1ResBody" - } - } - } - } - }, - "securitySchemes": { - "bearerAuth": { - "type": "http", - "scheme": "bearer", - "bearerFormat": "JWT" - } - }, - "schemas": { - "authResponse": { - "type": "object", - "properties": { - "expiresIn": { - "type": "number", - "description": "TTL for the token in seconds", - "example": 3600 - }, - "expires": { - "type": "string", - "description": "ISO8601 compliant timestamp for the token expiry", - "format": "iso8601-timestamp", - "example": "2020-01-19T06:00:00+01:00" - }, - "token": { - "type": "string", - "description": "ready to use token for API queries", - "example": "ey..." - }, - "refreshToken": { - "type": "string", - "description": "refresh token to be used with `/auth/refresh`/ endpoint", - "example": "A0..." - }, - "user": { - "type": "object", - "description": "Firebase-type user object obtained by decoding the JWT token" - }, - "trace": { - "type": "string", - "example": null - } - } - }, - "errorBadRequest": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "request.body should have required property 'XYZ'" - }, - "errors": { - "type": "array", - "minItems": 1, - "items": { - "type": "object", - "properties": { - "path": { - "type": "string", - "example": ".body.XYZ" - }, - "message": { - "type": "string", - "example": "should have required property 'XYZ'" - }, - "errorCode": { - "type": "string", - "example": "required.openapi.validation" - } - } - } - }, - "trace": { - "type": "string", - "example": null - } - } - }, - "errorUnauthorized": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "request.headers should have required property 'Authorization'" - }, - "errors": { - "type": "array", - "minItems": 1, - "items": { - "type": "object", - "properties": { - "path": { - "type": "string", - "example": ".headers.authorization" - }, - "message": { - "type": "string", - "example": "should have required property 'authorization'" - }, - "errorCode": { - "type": "string", - "example": "required.user" - } - } - } - }, - "trace": { - "type": "string", - "example": null - } - } - }, - "errorNotFound": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "object 'object.name' not found" - }, - "trace": { - "type": "string", - "example": null - } - } - }, - "errorForbidden": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "user is missing required permission" - }, - "errors": { - "type": "array", - "minItems": 1, - "items": { - "type": "object", - "properties": { - "path": { - "type": "string", - "example": ".headers.authorization" - }, - "message": { - "type": "string", - "example": "should have required permission" - }, - "errorCode": { - "type": "string", - "example": "required.user.permission" - } - } - } - }, - "trace": { - "type": "string", - "example": null - } - } - }, - "errorInternalServerError": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Internal Server Error" - }, - "trace": { - "type": "string", - "example": null - } - } - }, - "services": { - "type": "object", - "required": [ - "type", - "externalId", - "publisherId" - ], - "properties": { - "type": { - "type": "string", - "example": "PermanentLivestream", - "enum": [ - "EventLivestream", - "PermanentLivestream" - ] - }, - "externalId": { - "type": "string", - "example": "crid://swr.de/123450" - }, - "publisherId": { - "type": "string", - "description": "External ID or globally unique identifier (Core ID) for the associated publisher.\nWhen no Core ID is provided, the External ID will be converted by Eventhub.\n", - "example": "248000" - }, - "id": { - "type": "string", - "description": "Globally unique identifier, created by Eventhub", - "example": "urn:ard:permanent-livestream:49267f7d67be180d" - } - } - }, - "eventV1PostBody": { - "additionalProperties": false, - "required": [ - "type", - "start", - "title", - "services", - "playlistItemId" - ], - "type": "object", - "description": "**Please also note the details in the `POST /events/v1` endpoint above!**\n", - "properties": { - "event": { - "type": "string", - "description": "If set, it needs to match the URL event parameter", - "example": "de.ard.eventhub.v1.radio.track.playing", - "enum": [ - "de.ard.eventhub.v1.radio.track.playing", - "de.ard.eventhub.v1.radio.track.next" - ] - }, - "type": { - "type": "string", - "description": "The type of the element that triggered this event. See additional file in docs for details.", - "example": "music", - "enum": [ - "audio", - "commercial", - "jingle", - "live", - "music", - "news", - "traffic", - "weather" - ] - }, - "start": { - "type": "string", - "description": "ISO8601 compliant timestamp", - "format": "iso8601-timestamp", - "example": "2020-01-19T06:00:00+01:00" - }, - "length": { - "type": "number", - "format": "float", - "description": "Scheduled length of the element in seconds", - "example": 240, - "nullable": true - }, - "title": { - "type": "string", - "description": "Representative title for external use", - "example": "Song name" - }, - "artist": { - "type": "string", - "description": "Pre-formatted artist information", - "example": "Sam Feldt feat. Someone Else", - "nullable": true - }, - "contributors": { - "type": "array", - "description": "Full details about involved artists if available", - "nullable": true, - "items": { - "type": "object", - "required": [ - "name", - "role" - ], - "properties": { - "name": { - "type": "string", - "example": "Sam Feldt" - }, - "role": { - "type": "string", - "example": "artist", - "enum": [ - "artist", - "author", - "composer", - "performer" - ] - }, - "normDb": { - "type": "object", - "description": "Reference to an entity in ARD's Norm-DB catalog", - "nullable": true, - "properties": { - "type": { - "type": "string", - "example": "Person" - }, - "id": { - "type": "string", - "example": "1641010" - } - } - }, - "isni": { - "type": "string", - "description": "ISNI ID if available", - "nullable": true, - "externalDocs": { - "description": "International Standard Name Identifier", - "url": "https://kb.ddex.net/display/HBK/Communication+of+Identifiers+in+DDEX+Messages" - } - }, - "url": { - "type": "string", - "description": "Can link to external reference", - "nullable": true - } - } - } - }, - "services": { - "type": "array", - "description": "The playing stations unique Service-IDs. Do not include the Service-Type suffix.", - "items": { - "minItems": 1, - "allOf": [ - { - "$ref": "#/components/schemas/services" - } - ] - } - }, - "playlistItemId": { - "type": "string", - "description": "Unique identifier (within a publisher) to connect next and playing items if needed", - "example": "swr3-5678" - }, - "hfdbIds": { - "type": "array", - "description": "Can reference all available tracks in ARD HFDB instances. Should ideally at least include the common ZSK instance.", - "nullable": true, - "items": { - "type": "string" - }, - "example": [ - "swrhfdb1.KONF.12345", - "zskhfdb1.KONF.12345" - ] - }, - "externalId": { - "type": "string", - "description": "Can reference the original ID in the publisher's system", - "example": "M012345.001", - "nullable": true - }, - "isrc": { - "type": "string", - "description": "Appropriate ISRC code if track is a music element", - "example": "DE012345678", - "nullable": true - }, - "upc": { - "type": "string", - "description": "Corresponding reference to an album where such ISRC was published", - "nullable": true - }, - "mpn": { - "type": "string", - "description": "If available the reference to the original delivery from MPN", - "nullable": true - }, - "media": { - "type": "array", - "description": "Can contain an array of media files like cover, artist, etc.", - "nullable": true, - "items": { - "required": [ - "type", - "url", - "description" - ], - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "cover", - "artist", - "anchor", - "audio", - "video" - ], - "example": "cover" - }, - "url": { - "type": "string", - "example": "https://example.com/cover.jpg" - }, - "templateUrl": { - "type": "string", - "example": "https://example.com/cover.jpg?width={width}", - "nullable": true - }, - "description": { - "type": "string", - "example": "Cover Demo Artist" - }, - "attribution": { - "type": "string", - "example": "Photographer XYZ", - "nullable": true - } - } - } - }, - "plugins": { - "type": "array", - "description": "Highly optional field for future third-party metadata distribution or other connected services", - "nullable": true, - "items": { - "type": "object", - "properties": { - "type": { - "type": "string", - "example": "postToThirdPartyPlatformXYZ" - } - } - } - }, - "id": { - "type": "string", - "description": "ID gets inserted by Eventhub as string-formatted number, but might be a true string in the future, do not expect this string to remain numbers only!", - "example": "1234567890" - } - } - }, - "eventV1ResBody": { - "type": "object", - "properties": { - "statuses": { - "type": "object", - "properties": { - "published": { - "type": "integer", - "example": 1 - }, - "blocked": { - "type": "integer", - "example": 0 - }, - "failed": { - "type": "integer", - "example": 0 - } - } - }, - "event": { - "$ref": "#/components/schemas/eventV1PostBody" - }, - "trace": { - "type": "string", - "example": null - } - } - }, - "subscriptionPost": { - "required": [ - "type", - "method", - "url", - "contact", - "topic" - ], - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "PUBSUB" - ], - "example": "PUBSUB" - }, - "method": { - "type": "string", - "enum": [ - "PUSH" - ], - "example": "PUSH" - }, - "url": { - "type": "string", - "description": "Publicly accessible URL that should receive the events", - "example": "https://example.com/my/webhook/for/this/subscription" - }, - "contact": { - "type": "string", - "description": "Email address to be contacted in case of problems with this subscription", - "example": "my-emergency-and-notifications-contact@ard.de" - }, - "topic": { - "type": "string", - "description": "ID of the topic to subscribe to", - "example": "topic-id-to-subscribe-to" - } - } - }, - "subscriptionsList": { - "type": "array", - "items": { - "allOf": [ - { - "$ref": "#/components/schemas/subscriptionResponse" - } - ] - } - }, - "subscriptionResponse": { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "PUBSUB" - ], - "example": "PUBSUB" - }, - "method": { - "type": "string", - "enum": [ - "PUSH" - ], - "example": "PUSH" - }, - "name": { - "type": "string", - "description": "ID of the subscription to be referenced in API calls", - "example": "de.ard.eventhub.subscription.subscription-id" - }, - "path": { - "type": "string", - "description": "Path of subscription in project", - "example": "projects/ard-eventhub/subscriptions/subscription-name" - }, - "topic": { - "type": "object", - "description": "Object of the subscribed topic", - "properties": { - "id": { - "type": "string", - "example": "urn:ard:permanent-livestream:topic-id" - }, - "name": { - "type": "string", - "example": "de.ard.eventhub.dev.urn%3Aard%3Apermanent-livestream%3Atopic-id" - }, - "path": { - "type": "string", - "example": "projects/ard-eventhub/topics/topic-name" - } - } - }, - "ackDeadlineSeconds": { - "type": "integer", - "example": 20 - }, - "retryPolicy": { - "type": "string", - "example": null - }, - "serviceAccount": { - "type": "string", - "example": "name-of-service-account" - }, - "url": { - "type": "string", - "description": "Publicly accessible URL that should receive the events", - "example": "https://example.com/my/webhook/for/this/subscription" - }, - "contact": { - "type": "string", - "description": "Email address to be contacted in case of problems with this subscription", - "example": "my-emergency-and-notifications-contact@ard.de" - }, - "institutionId": { - "type": "string", - "description": "ID of the institution the current user belongs to", - "example": "urn:ard:institution:institution-id" - } - } - }, - "subscriptionDeleted": { - "type": "object", - "properties": { - "valid": { - "type": "boolean", - "example": true - }, - "trace": { - "type": "string", - "example": null - } - } - }, - "topicResponse": { - "type": "array", - "items": { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "PUBSUB" - ], - "example": "PUBSUB" - }, - "id": { - "type": "string", - "example": "urn:ard:permanent-livestream:topic-id" - }, - "name": { - "type": "string", - "example": "de.ard.eventhub.dev.urn%3Aard%3Apermanent-livestream%3Atopic-id" - }, - "path": { - "type": "string", - "example": "projects/ard-eventhub/topics/topic-name" - }, - "labels": { - "type": "object", - "properties": { - "id": { - "type": "string", - "example": "1234567890" - }, - "creator-slug": { - "type": "string", - "example": "ard-eventhub-swr" - }, - "publisher-slug": { - "type": "string", - "example": "swr-rheinland-pfalz" - }, - "stage": { - "type": "string", - "example": "prod" - }, - "created": { - "type": "string", - "example": "2021-03-25" - }, - "institution-slug": { - "type": "string", - "example": "sudwestrundfunk" - } - } - } - } - } - } - } - } -} \ No newline at end of file + "openapi": "3.0.3", + "info": { + "title": "ARD-Eventhub", + "description": "ARD system to distribute real-time (live) metadata for primarily radio broadcasts.", + "termsOfService": "https://www.ard.de", + "contact": { + "email": "lab@swr.de" + }, + "license": { + "name": "European Union Public License 1.2", + "url": "https://spdx.org/licenses/EUPL-1.2.html" + }, + "version": "1.3.8" + }, + "externalDocs": { + "description": "ARD-Eventhub Documentation", + "url": "https://swrlab.github.io/ard-eventhub/" + }, + "servers": [ + { + "url": "/", + "description": "Local (domain-relative) environment" + } + ], + "tags": [ + { + "name": "auth", + "description": "Authentication services for Eventhub" + }, + { + "name": "events", + "description": "Manage events" + }, + { + "name": "subscriptions", + "description": "Access to subscription management" + }, + { + "name": "topics", + "description": "Access to topics details" + } + ], + "paths": { + "/auth/login": { + "post": { + "tags": ["auth"], + "summary": "Swap login credentials for a token", + "operationId": "authLoginPost", + "requestBody": { + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "type": "object", + "properties": { + "email": { + "type": "string", + "example": "my-email@example.com" + }, + "password": { + "type": "string", + "example": "my-password" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Authentication successful", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/authResponse" + } + } + } + }, + "400": { + "description": "Bad Request (invalid input)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/errorBadRequest" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/errorInternalServerError" + } + } + } + } + } + } + }, + "/auth/refresh": { + "post": { + "tags": ["auth"], + "summary": "Swap refresh token for new id token", + "operationId": "authRefreshPost", + "requestBody": { + "content": { + "application/json": { + "schema": { + "additionalProperties": false, + "type": "object", + "properties": { + "refreshToken": { + "type": "string", + "example": "abcXYZ..." + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Authentication successful", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/authResponse" + } + } + } + }, + "400": { + "description": "Bad Request (invalid input)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/errorBadRequest" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/errorInternalServerError" + } + } + } + } + } + } + }, + "/auth/reset": { + "post": { + "tags": ["auth"], + "summary": "Request password reset email", + "operationId": "authResetPost", + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "type": "string", + "example": "my-email@example.com" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Request successful", + "content": {} + }, + "400": { + "description": "Bad Request (invalid input)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/errorBadRequest" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/errorInternalServerError" + } + } + } + } + } + } + }, + "/events/de.ard.eventhub.v1.radio.track.next": { + "post": { + "tags": ["events"], + "summary": "Distribute a next track", + "operationId": "eventPostV1RadioTrackNext", + "security": [ + { + "bearerAuth": [] + } + ], + "requestBody": { + "$ref": "#/components/requestBodies/eventV1RadioTrack" + }, + "responses": { + "201": { + "$ref": "#/components/responses/eventV1RadioTrack" + }, + "400": { + "description": "Bad Request (invalid input)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/errorBadRequest" + } + } + } + }, + "401": { + "description": "Missing authentication", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/errorUnauthorized" + } + } + } + }, + "403": { + "description": "Invalid authorization", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/errorForbidden" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/errorInternalServerError" + } + } + } + } + } + } + }, + "/events/de.ard.eventhub.v1.radio.track.playing": { + "post": { + "tags": ["events"], + "summary": "Distribute a now-playing track", + "operationId": "eventPostV1RadioTrackPlaying", + "security": [ + { + "bearerAuth": [] + } + ], + "requestBody": { + "$ref": "#/components/requestBodies/eventV1RadioTrack" + }, + "responses": { + "201": { + "$ref": "#/components/responses/eventV1RadioTrack" + }, + "400": { + "description": "Bad Request (invalid input)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/errorBadRequest" + } + } + } + }, + "401": { + "description": "Missing authentication", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/errorUnauthorized" + } + } + } + }, + "403": { + "description": "Invalid authorization", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/errorForbidden" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/errorInternalServerError" + } + } + } + } + } + } + }, + "/subscriptions": { + "get": { + "tags": ["subscriptions"], + "summary": "List all subscriptions for this user", + "operationId": "subscriptionList", + "security": [ + { + "bearerAuth": [] + } + ], + "responses": { + "200": { + "description": "Subscriptions found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/subscriptionsList" + } + } + } + }, + "401": { + "description": "Missing authentication", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/errorUnauthorized" + } + } + } + }, + "403": { + "description": "Invalid authorization", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/errorForbidden" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/errorInternalServerError" + } + } + } + } + } + }, + "post": { + "tags": ["subscriptions"], + "summary": "Add a new subscription", + "operationId": "subscriptionPost", + "security": [ + { + "bearerAuth": [] + } + ], + "requestBody": { + "description": "New event to be distributed to subscribers.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/subscriptionPost" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Subscription created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/subscriptionResponse" + } + } + } + }, + "400": { + "description": "Bad Request (invalid input)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/errorBadRequest" + } + } + } + }, + "401": { + "description": "Missing authentication", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/errorUnauthorized" + } + } + } + }, + "403": { + "description": "Invalid authorization", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/errorForbidden" + } + } + } + }, + "404": { + "description": "Topic for subscription not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/errorNotFound" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/errorInternalServerError" + } + } + } + } + } + } + }, + "/subscriptions/{name}": { + "get": { + "tags": ["subscriptions"], + "summary": "Get details about a single subscription from this user", + "operationId": "subscriptionsGet", + "security": [ + { + "bearerAuth": [] + } + ], + "parameters": [ + { + "name": "name", + "in": "path", + "description": "`name` of the desired subscription", + "required": true, + "style": "simple", + "explode": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Subscription found", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/subscriptionResponse" + } + } + } + } + }, + "401": { + "description": "Missing authentication", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/errorUnauthorized" + } + } + } + }, + "403": { + "description": "Invalid authorization", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/errorForbidden" + } + } + } + }, + "404": { + "description": "Subscription not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/errorNotFound" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/errorInternalServerError" + } + } + } + } + } + }, + "delete": { + "tags": ["subscriptions"], + "summary": "Remove a single subscription by this user", + "operationId": "subscriptionsDelete", + "security": [ + { + "bearerAuth": [] + } + ], + "parameters": [ + { + "name": "name", + "in": "path", + "description": "`name` of the desired subscription", + "required": true, + "style": "simple", + "explode": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Subscription deleted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/subscriptionDeleted" + } + } + } + }, + "401": { + "description": "Missing authentication", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/errorUnauthorized" + } + } + } + }, + "403": { + "description": "Invalid authorization", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/errorForbidden" + } + } + } + }, + "404": { + "description": "Subscription not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/errorNotFound" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/errorInternalServerError" + } + } + } + } + } + } + }, + "/topics": { + "get": { + "tags": ["topics"], + "summary": "List all available topics", + "operationId": "topicsGet", + "security": [ + { + "bearerAuth": [] + } + ], + "responses": { + "200": { + "description": "Topics found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/topicResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/errorInternalServerError" + } + } + } + } + } + } + } + }, + "components": { + "requestBodies": { + "eventV1RadioTrack": { + "description": "New event to be distributed to subscribers. \n \nThe Eventhub format validation expects only a subset of these variables as minimum set. All other fields are technically optional, but **highly encouraged** to be included, so a best-possible metadata exchange is possible. \nThe subset is defined in the list of required fields of Schemas `eventV1PostBody`, resulting in this body: \n```json\n{\n \"type\": \"music\",\n \"start\": \"2020-01-19T06:00:00+01:00\",\n \"title\": \"Song name\",\n \"services\": [ { ... } ],\n \"playlistItemId\": \"swr3-5678\"\n}\n```\nRequired fields not specified in the Schema, will cause your request to fail. \n \nThe `id` is inserted by Eventhub as string-formatted number, but might be a true string in the future, do not expect this string to remain numbers only!\n", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/eventV1PostBody" + } + } + }, + "required": true + } + }, + "responses": { + "eventV1RadioTrack": { + "description": "Event created \n \n*Note:* The first request of an event for an externalId that is not registered yet, will return the status `failed: 1`. This indicates that a new topic for the externalId has been created, and the request needs to be repeated:\n```json\n\"statuses\": {\n \"published\": 0,\n \"blocked\": 0,\n \"failed\": 1\n}\n```\nIf the request returns the status `blocked: 1`, it indicates that you are not allowed to publish events under the given publisherId.\n", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/eventV1ResBody" + } + } + } + } + }, + "securitySchemes": { + "bearerAuth": { + "type": "http", + "scheme": "bearer", + "bearerFormat": "JWT" + } + }, + "schemas": { + "authResponse": { + "type": "object", + "properties": { + "expiresIn": { + "type": "number", + "description": "TTL for the token in seconds", + "example": 3600 + }, + "expires": { + "type": "string", + "description": "ISO8601 compliant timestamp for the token expiry", + "format": "iso8601-timestamp", + "example": "2020-01-19T06:00:00+01:00" + }, + "token": { + "type": "string", + "description": "ready to use token for API queries", + "example": "ey..." + }, + "refreshToken": { + "type": "string", + "description": "refresh token to be used with `/auth/refresh`/ endpoint", + "example": "A0..." + }, + "user": { + "type": "object", + "description": "Firebase-type user object obtained by decoding the JWT token" + }, + "trace": { + "type": "string", + "example": null + } + } + }, + "errorBadRequest": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "request.body should have required property 'XYZ'" + }, + "errors": { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "properties": { + "path": { + "type": "string", + "example": ".body.XYZ" + }, + "message": { + "type": "string", + "example": "should have required property 'XYZ'" + }, + "errorCode": { + "type": "string", + "example": "required.openapi.validation" + } + } + } + }, + "trace": { + "type": "string", + "example": null + } + } + }, + "errorUnauthorized": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "request.headers should have required property 'Authorization'" + }, + "errors": { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "properties": { + "path": { + "type": "string", + "example": ".headers.authorization" + }, + "message": { + "type": "string", + "example": "should have required property 'authorization'" + }, + "errorCode": { + "type": "string", + "example": "required.user" + } + } + } + }, + "trace": { + "type": "string", + "example": null + } + } + }, + "errorNotFound": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "object 'object.name' not found" + }, + "trace": { + "type": "string", + "example": null + } + } + }, + "errorForbidden": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "user is missing required permission" + }, + "errors": { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "properties": { + "path": { + "type": "string", + "example": ".headers.authorization" + }, + "message": { + "type": "string", + "example": "should have required permission" + }, + "errorCode": { + "type": "string", + "example": "required.user.permission" + } + } + } + }, + "trace": { + "type": "string", + "example": null + } + } + }, + "errorInternalServerError": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Internal Server Error" + }, + "trace": { + "type": "string", + "example": null + } + } + }, + "services": { + "type": "object", + "required": ["type", "externalId", "publisherId"], + "properties": { + "type": { + "type": "string", + "example": "PermanentLivestream", + "enum": ["EventLivestream", "PermanentLivestream"] + }, + "externalId": { + "type": "string", + "example": "crid://swr.de/123450" + }, + "publisherId": { + "type": "string", + "description": "External ID or globally unique identifier (Core ID) for the associated publisher.\nWhen no Core ID is provided, the External ID will be converted by Eventhub.\n", + "example": "248000" + }, + "id": { + "type": "string", + "description": "Globally unique identifier, created by Eventhub", + "example": "urn:ard:permanent-livestream:49267f7d67be180d" + } + } + }, + "eventV1PostBody": { + "additionalProperties": false, + "required": ["type", "start", "title", "services", "playlistItemId"], + "type": "object", + "description": "**Please also note the details in the `POST /events/v1` endpoint above!**\n", + "properties": { + "event": { + "type": "string", + "description": "If set, it needs to match the URL event parameter", + "example": "de.ard.eventhub.v1.radio.track.playing", + "enum": [ + "de.ard.eventhub.v1.radio.track.playing", + "de.ard.eventhub.v1.radio.track.next" + ] + }, + "type": { + "type": "string", + "description": "The type of the element that triggered this event. See additional file in docs for details.", + "example": "music", + "enum": [ + "audio", + "commercial", + "jingle", + "live", + "music", + "news", + "traffic", + "weather" + ] + }, + "start": { + "type": "string", + "description": "ISO8601 compliant timestamp", + "format": "iso8601-timestamp", + "example": "2020-01-19T06:00:00+01:00" + }, + "length": { + "type": "number", + "format": "float", + "description": "Scheduled length of the element in seconds", + "example": 240, + "nullable": true + }, + "title": { + "type": "string", + "description": "Representative title for external use", + "example": "Song name" + }, + "artist": { + "type": "string", + "description": "Pre-formatted artist information", + "example": "Sam Feldt feat. Someone Else", + "nullable": true + }, + "contributors": { + "type": "array", + "description": "Full details about involved artists if available", + "nullable": true, + "items": { + "type": "object", + "required": ["name", "role"], + "properties": { + "name": { + "type": "string", + "example": "Sam Feldt" + }, + "role": { + "type": "string", + "example": "artist", + "enum": [ + "artist", + "author", + "composer", + "performer" + ] + }, + "normDb": { + "type": "object", + "description": "Reference to an entity in ARD's Norm-DB catalog", + "nullable": true, + "properties": { + "type": { + "type": "string", + "example": "Person" + }, + "id": { + "type": "string", + "example": "1641010" + } + } + }, + "isni": { + "type": "string", + "description": "ISNI ID if available", + "nullable": true, + "externalDocs": { + "description": "International Standard Name Identifier", + "url": "https://kb.ddex.net/display/HBK/Communication+of+Identifiers+in+DDEX+Messages" + } + }, + "url": { + "type": "string", + "description": "Can link to external reference", + "nullable": true + } + } + } + }, + "services": { + "type": "array", + "description": "The playing stations unique Service-IDs. Do not include the Service-Type suffix.", + "items": { + "minItems": 1, + "allOf": [ + { + "$ref": "#/components/schemas/services" + } + ] + } + }, + "playlistItemId": { + "type": "string", + "description": "Unique identifier (within a publisher) to connect next and playing items if needed", + "example": "swr3-5678" + }, + "hfdbIds": { + "type": "array", + "description": "Can reference all available tracks in ARD HFDB instances. Should ideally at least include the common ZSK instance.", + "nullable": true, + "items": { + "type": "string" + }, + "example": ["swrhfdb1.KONF.12345", "zskhfdb1.KONF.12345"] + }, + "externalId": { + "type": "string", + "description": "Can reference the original ID in the publisher's system", + "example": "M012345.001", + "nullable": true + }, + "isrc": { + "type": "string", + "description": "Appropriate ISRC code if track is a music element", + "example": "DE012345678", + "nullable": true + }, + "upc": { + "type": "string", + "description": "Corresponding reference to an album where such ISRC was published", + "nullable": true + }, + "mpn": { + "type": "string", + "description": "If available the reference to the original delivery from MPN", + "nullable": true + }, + "media": { + "type": "array", + "description": "Can contain an array of media files like cover, artist, etc.", + "nullable": true, + "items": { + "required": ["type", "url", "description"], + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "cover", + "artist", + "anchor", + "audio", + "video" + ], + "example": "cover" + }, + "url": { + "type": "string", + "example": "https://example.com/cover.jpg" + }, + "templateUrl": { + "type": "string", + "example": "https://example.com/cover.jpg?width={width}", + "nullable": true + }, + "description": { + "type": "string", + "example": "Cover Demo Artist" + }, + "attribution": { + "type": "string", + "example": "Photographer XYZ", + "nullable": true + } + } + } + }, + "plugins": { + "type": "array", + "description": "Highly optional field for future third-party metadata distribution or other connected services", + "nullable": true, + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "example": "postToThirdPartyPlatformXYZ" + } + } + } + }, + "id": { + "type": "string", + "description": "ID gets inserted by Eventhub as string-formatted number, but might be a true string in the future, do not expect this string to remain numbers only!", + "example": "1234567890" + } + } + }, + "eventV1ResBody": { + "type": "object", + "properties": { + "statuses": { + "type": "object", + "properties": { + "published": { + "type": "integer", + "example": 1 + }, + "blocked": { + "type": "integer", + "example": 0 + }, + "failed": { + "type": "integer", + "example": 0 + } + } + }, + "event": { + "$ref": "#/components/schemas/eventV1PostBody" + }, + "trace": { + "type": "string", + "example": null + } + } + }, + "subscriptionPost": { + "required": ["type", "method", "url", "contact", "topic"], + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["PUBSUB"], + "example": "PUBSUB" + }, + "method": { + "type": "string", + "enum": ["PUSH"], + "example": "PUSH" + }, + "url": { + "type": "string", + "description": "Publicly accessible URL that should receive the events", + "example": "https://example.com/my/webhook/for/this/subscription" + }, + "contact": { + "type": "string", + "description": "Email address to be contacted in case of problems with this subscription", + "example": "my-emergency-and-notifications-contact@ard.de" + }, + "topic": { + "type": "string", + "description": "ID of the topic to subscribe to", + "example": "topic-id-to-subscribe-to" + } + } + }, + "subscriptionsList": { + "type": "array", + "items": { + "allOf": [ + { + "$ref": "#/components/schemas/subscriptionResponse" + } + ] + } + }, + "subscriptionResponse": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["PUBSUB"], + "example": "PUBSUB" + }, + "method": { + "type": "string", + "enum": ["PUSH"], + "example": "PUSH" + }, + "name": { + "type": "string", + "description": "ID of the subscription to be referenced in API calls", + "example": "de.ard.eventhub.subscription.subscription-id" + }, + "path": { + "type": "string", + "description": "Path of subscription in project", + "example": "projects/ard-eventhub/subscriptions/subscription-name" + }, + "topic": { + "type": "object", + "description": "Object of the subscribed topic", + "properties": { + "id": { + "type": "string", + "example": "urn:ard:permanent-livestream:topic-id" + }, + "name": { + "type": "string", + "example": "de.ard.eventhub.dev.urn%3Aard%3Apermanent-livestream%3Atopic-id" + }, + "path": { + "type": "string", + "example": "projects/ard-eventhub/topics/topic-name" + } + } + }, + "ackDeadlineSeconds": { + "type": "integer", + "example": 20 + }, + "retryPolicy": { + "type": "string", + "example": null + }, + "serviceAccount": { + "type": "string", + "example": "name-of-service-account" + }, + "url": { + "type": "string", + "description": "Publicly accessible URL that should receive the events", + "example": "https://example.com/my/webhook/for/this/subscription" + }, + "contact": { + "type": "string", + "description": "Email address to be contacted in case of problems with this subscription", + "example": "my-emergency-and-notifications-contact@ard.de" + }, + "institutionId": { + "type": "string", + "description": "ID of the institution the current user belongs to", + "example": "urn:ard:institution:institution-id" + } + } + }, + "subscriptionDeleted": { + "type": "object", + "properties": { + "valid": { + "type": "boolean", + "example": true + }, + "trace": { + "type": "string", + "example": null + } + } + }, + "topicResponse": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["PUBSUB"], + "example": "PUBSUB" + }, + "id": { + "type": "string", + "example": "urn:ard:permanent-livestream:topic-id" + }, + "name": { + "type": "string", + "example": "de.ard.eventhub.dev.urn%3Aard%3Apermanent-livestream%3Atopic-id" + }, + "path": { + "type": "string", + "example": "projects/ard-eventhub/topics/topic-name" + }, + "labels": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "1234567890" + }, + "creator-slug": { + "type": "string", + "example": "ard-eventhub-swr" + }, + "publisher-slug": { + "type": "string", + "example": "swr-rheinland-pfalz" + }, + "stage": { + "type": "string", + "example": "prod" + }, + "created": { + "type": "string", + "example": "2021-03-25" + }, + "institution-slug": { + "type": "string", + "example": "sudwestrundfunk" + } + } + } + } + } + } + } + } +} diff --git a/openapi.yaml b/openapi.yaml index 8d99cb69..80a74837 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -4,16 +4,16 @@ info: description: >- ARD system to distribute real-time (live) metadata for primarily radio broadcasts. - termsOfService: 'https://www.ard.de' + termsOfService: "https://www.ard.de" contact: email: lab@swr.de license: name: European Union Public License 1.2 - url: 'https://spdx.org/licenses/EUPL-1.2.html' - version: 1.3.7 + url: "https://spdx.org/licenses/EUPL-1.2.html" + version: 1.3.8 externalDocs: description: ARD-Eventhub Documentation - url: 'https://swrlab.github.io/ard-eventhub/' + url: "https://swrlab.github.io/ard-eventhub/" servers: - url: / description: Local (domain-relative) environment @@ -47,24 +47,24 @@ paths: type: string example: my-password responses: - '200': + "200": description: Authentication successful content: application/json: schema: - $ref: '#/components/schemas/authResponse' - '400': + $ref: "#/components/schemas/authResponse" + "400": description: Bad Request (invalid input) content: application/json: schema: - $ref: '#/components/schemas/errorBadRequest' - '500': + $ref: "#/components/schemas/errorBadRequest" + "500": description: Internal server error content: application/json: schema: - $ref: '#/components/schemas/errorInternalServerError' + $ref: "#/components/schemas/errorInternalServerError" /auth/refresh: post: tags: @@ -82,24 +82,24 @@ paths: type: string example: abcXYZ... responses: - '200': + "200": description: Authentication successful content: application/json: schema: - $ref: '#/components/schemas/authResponse' - '400': + $ref: "#/components/schemas/authResponse" + "400": description: Bad Request (invalid input) content: application/json: schema: - $ref: '#/components/schemas/errorBadRequest' - '500': + $ref: "#/components/schemas/errorBadRequest" + "500": description: Internal server error content: application/json: schema: - $ref: '#/components/schemas/errorInternalServerError' + $ref: "#/components/schemas/errorInternalServerError" /auth/reset: post: tags: @@ -116,22 +116,22 @@ paths: type: string example: my-email@example.com responses: - '200': + "200": description: Request successful content: {} - '400': + "400": description: Bad Request (invalid input) content: application/json: schema: - $ref: '#/components/schemas/errorBadRequest' - '500': + $ref: "#/components/schemas/errorBadRequest" + "500": description: Internal server error content: application/json: schema: - $ref: '#/components/schemas/errorInternalServerError' - '/events/de.ard.eventhub.v1.radio.track.next': + $ref: "#/components/schemas/errorInternalServerError" + "/events/de.ard.eventhub.v1.radio.track.next": post: tags: - events @@ -140,35 +140,35 @@ paths: security: - bearerAuth: [] requestBody: - $ref: '#/components/requestBodies/eventV1RadioTrack' + $ref: "#/components/requestBodies/eventV1RadioTrack" responses: - '201': - $ref: '#/components/responses/eventV1RadioTrack' - '400': + "201": + $ref: "#/components/responses/eventV1RadioTrack" + "400": description: Bad Request (invalid input) content: application/json: schema: - $ref: '#/components/schemas/errorBadRequest' - '401': + $ref: "#/components/schemas/errorBadRequest" + "401": description: Missing authentication content: application/json: schema: - $ref: '#/components/schemas/errorUnauthorized' - '403': + $ref: "#/components/schemas/errorUnauthorized" + "403": description: Invalid authorization content: application/json: schema: - $ref: '#/components/schemas/errorForbidden' - '500': + $ref: "#/components/schemas/errorForbidden" + "500": description: Internal server error content: application/json: schema: - $ref: '#/components/schemas/errorInternalServerError' - '/events/de.ard.eventhub.v1.radio.track.playing': + $ref: "#/components/schemas/errorInternalServerError" + "/events/de.ard.eventhub.v1.radio.track.playing": post: tags: - events @@ -177,34 +177,34 @@ paths: security: - bearerAuth: [] requestBody: - $ref: '#/components/requestBodies/eventV1RadioTrack' + $ref: "#/components/requestBodies/eventV1RadioTrack" responses: - '201': - $ref: '#/components/responses/eventV1RadioTrack' - '400': + "201": + $ref: "#/components/responses/eventV1RadioTrack" + "400": description: Bad Request (invalid input) content: application/json: schema: - $ref: '#/components/schemas/errorBadRequest' - '401': + $ref: "#/components/schemas/errorBadRequest" + "401": description: Missing authentication content: application/json: schema: - $ref: '#/components/schemas/errorUnauthorized' - '403': + $ref: "#/components/schemas/errorUnauthorized" + "403": description: Invalid authorization content: application/json: schema: - $ref: '#/components/schemas/errorForbidden' - '500': + $ref: "#/components/schemas/errorForbidden" + "500": description: Internal server error content: application/json: schema: - $ref: '#/components/schemas/errorInternalServerError' + $ref: "#/components/schemas/errorInternalServerError" /subscriptions: get: tags: @@ -214,30 +214,30 @@ paths: security: - bearerAuth: [] responses: - '200': + "200": description: Subscriptions found content: application/json: schema: - $ref: '#/components/schemas/subscriptionsList' - '401': + $ref: "#/components/schemas/subscriptionsList" + "401": description: Missing authentication content: application/json: schema: - $ref: '#/components/schemas/errorUnauthorized' - '403': + $ref: "#/components/schemas/errorUnauthorized" + "403": description: Invalid authorization content: application/json: schema: - $ref: '#/components/schemas/errorForbidden' - '500': + $ref: "#/components/schemas/errorForbidden" + "500": description: Internal server error content: application/json: schema: - $ref: '#/components/schemas/errorInternalServerError' + $ref: "#/components/schemas/errorInternalServerError" post: tags: - subscriptions @@ -250,46 +250,46 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/subscriptionPost' + $ref: "#/components/schemas/subscriptionPost" required: true responses: - '201': + "201": description: Subscription created content: application/json: schema: - $ref: '#/components/schemas/subscriptionResponse' - '400': + $ref: "#/components/schemas/subscriptionResponse" + "400": description: Bad Request (invalid input) content: application/json: schema: - $ref: '#/components/schemas/errorBadRequest' - '401': + $ref: "#/components/schemas/errorBadRequest" + "401": description: Missing authentication content: application/json: schema: - $ref: '#/components/schemas/errorUnauthorized' - '403': + $ref: "#/components/schemas/errorUnauthorized" + "403": description: Invalid authorization content: application/json: schema: - $ref: '#/components/schemas/errorForbidden' - '404': + $ref: "#/components/schemas/errorForbidden" + "404": description: Topic for subscription not found content: application/json: schema: - $ref: '#/components/schemas/errorNotFound' - '500': + $ref: "#/components/schemas/errorNotFound" + "500": description: Internal server error content: application/json: schema: - $ref: '#/components/schemas/errorInternalServerError' - '/subscriptions/{name}': + $ref: "#/components/schemas/errorInternalServerError" + "/subscriptions/{name}": get: tags: - subscriptions @@ -300,45 +300,45 @@ paths: parameters: - name: name in: path - description: '`name` of the desired subscription' + description: "`name` of the desired subscription" required: true style: simple explode: false schema: type: string responses: - '200': + "200": description: Subscription found content: application/json: schema: type: array items: - $ref: '#/components/schemas/subscriptionResponse' - '401': + $ref: "#/components/schemas/subscriptionResponse" + "401": description: Missing authentication content: application/json: schema: - $ref: '#/components/schemas/errorUnauthorized' - '403': + $ref: "#/components/schemas/errorUnauthorized" + "403": description: Invalid authorization content: application/json: schema: - $ref: '#/components/schemas/errorForbidden' - '404': + $ref: "#/components/schemas/errorForbidden" + "404": description: Subscription not found content: application/json: schema: - $ref: '#/components/schemas/errorNotFound' - '500': + $ref: "#/components/schemas/errorNotFound" + "500": description: Internal server error content: application/json: schema: - $ref: '#/components/schemas/errorInternalServerError' + $ref: "#/components/schemas/errorInternalServerError" delete: tags: - subscriptions @@ -349,43 +349,43 @@ paths: parameters: - name: name in: path - description: '`name` of the desired subscription' + description: "`name` of the desired subscription" required: true style: simple explode: false schema: type: string responses: - '200': + "200": description: Subscription deleted content: application/json: schema: - $ref: '#/components/schemas/subscriptionDeleted' - '401': + $ref: "#/components/schemas/subscriptionDeleted" + "401": description: Missing authentication content: application/json: schema: - $ref: '#/components/schemas/errorUnauthorized' - '403': + $ref: "#/components/schemas/errorUnauthorized" + "403": description: Invalid authorization content: application/json: schema: - $ref: '#/components/schemas/errorForbidden' - '404': + $ref: "#/components/schemas/errorForbidden" + "404": description: Subscription not found content: application/json: schema: - $ref: '#/components/schemas/errorNotFound' - '500': + $ref: "#/components/schemas/errorNotFound" + "500": description: Internal server error content: application/json: schema: - $ref: '#/components/schemas/errorInternalServerError' + $ref: "#/components/schemas/errorInternalServerError" /topics: get: tags: @@ -395,18 +395,18 @@ paths: security: - bearerAuth: [] responses: - '200': + "200": description: Topics found content: application/json: schema: - $ref: '#/components/schemas/topicResponse' - '500': + $ref: "#/components/schemas/topicResponse" + "500": description: Internal server error content: application/json: schema: - $ref: '#/components/schemas/errorInternalServerError' + $ref: "#/components/schemas/errorInternalServerError" components: requestBodies: eventV1RadioTrack: @@ -442,7 +442,7 @@ components: content: application/json: schema: - $ref: '#/components/schemas/eventV1PostBody' + $ref: "#/components/schemas/eventV1PostBody" required: true responses: eventV1RadioTrack: @@ -453,24 +453,24 @@ components: registered yet, will return the status `failed: 1`. This indicates that a new topic for the externalId has been created, and the request needs to be repeated: - + ```json - + "statuses": { "published": 0, "blocked": 0, "failed": 1 } - + ``` - + If the request returns the status `blocked: 1`, it indicates that you are not allowed to publish events under the given publisherId. - + content: application/json: schema: - $ref: '#/components/schemas/eventV1ResBody' + $ref: "#/components/schemas/eventV1ResBody" securitySchemes: bearerAuth: type: http @@ -488,7 +488,7 @@ components: type: string description: ISO8601 compliant timestamp for the token expiry format: iso8601-timestamp - example: '2020-01-19T06:00:00+01:00' + example: "2020-01-19T06:00:00+01:00" token: type: string description: ready to use token for API queries @@ -603,24 +603,24 @@ components: properties: type: type: string - example: 'PermanentLivestream' + example: "PermanentLivestream" enum: - - 'EventLivestream' - - 'PermanentLivestream' + - "EventLivestream" + - "PermanentLivestream" externalId: type: string - example: 'crid://swr.de/123450' + example: "crid://swr.de/123450" publisherId: type: string description: | External ID or globally unique identifier (Core ID) for the associated publisher. When no Core ID is provided, the External ID will be converted by Eventhub. - example: '248000' + example: "248000" id: type: string description: Globally unique identifier, created by Eventhub - example: 'urn:ard:permanent-livestream:49267f7d67be180d' - + example: "urn:ard:permanent-livestream:49267f7d67be180d" + eventV1PostBody: additionalProperties: false required: @@ -660,7 +660,7 @@ components: type: string description: ISO8601 compliant timestamp format: iso8601-timestamp - example: '2020-01-19T06:00:00+01:00' + example: "2020-01-19T06:00:00+01:00" length: type: number format: float @@ -707,7 +707,7 @@ components: example: Person id: type: string - example: '1641010' + example: "1641010" isni: type: string description: ISNI ID if available @@ -728,7 +728,7 @@ components: items: minItems: 1 allOf: - - $ref: '#/components/schemas/services' + - $ref: "#/components/schemas/services" playlistItemId: type: string description: >- @@ -786,10 +786,10 @@ components: example: cover url: type: string - example: 'https://example.com/cover.jpg' + example: "https://example.com/cover.jpg" templateUrl: type: string - example: 'https://example.com/cover.jpg?width={width}' + example: "https://example.com/cover.jpg?width={width}" nullable: true description: type: string @@ -816,8 +816,8 @@ components: ID gets inserted by Eventhub as string-formatted number, but might be a true string in the future, do not expect this string to remain numbers only! - example: '1234567890' - + example: "1234567890" + eventV1ResBody: type: object properties: @@ -834,11 +834,11 @@ components: type: integer example: 0 event: - $ref: '#/components/schemas/eventV1PostBody' + $ref: "#/components/schemas/eventV1PostBody" trace: type: string example: null - + subscriptionPost: required: - type @@ -861,7 +861,7 @@ components: url: type: string description: Publicly accessible URL that should receive the events - example: 'https://example.com/my/webhook/for/this/subscription' + example: "https://example.com/my/webhook/for/this/subscription" contact: type: string description: >- @@ -872,13 +872,13 @@ components: type: string description: ID of the topic to subscribe to example: topic-id-to-subscribe-to - + subscriptionsList: type: array items: allOf: - - $ref: '#/components/schemas/subscriptionResponse' - + - $ref: "#/components/schemas/subscriptionResponse" + subscriptionResponse: type: object properties: @@ -925,7 +925,7 @@ components: url: type: string description: Publicly accessible URL that should receive the events - example: 'https://example.com/my/webhook/for/this/subscription' + example: "https://example.com/my/webhook/for/this/subscription" contact: type: string description: >- @@ -936,7 +936,7 @@ components: type: string description: ID of the institution the current user belongs to example: urn:ard:institution:institution-id - + subscriptionDeleted: type: object properties: @@ -946,7 +946,7 @@ components: trace: type: string example: null - + topicResponse: type: array items: @@ -969,7 +969,7 @@ components: labels: type: object properties: - id: + id: type: string example: "1234567890" creator-slug: @@ -978,12 +978,12 @@ components: publisher-slug: type: string example: swr-rheinland-pfalz - stage: + stage: type: string example: prod - created: + created: type: string example: "2021-03-25" - institution-slug: + institution-slug: type: string example: sudwestrundfunk diff --git a/package.json b/package.json index 99385fbe..ec05a8ae 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ard-eventhub", - "version": "1.3.7", + "version": "1.3.8", "description": "ARD system to distribute real-time (live) metadata for primarily radio broadcasts.", "main": "./src/ingest/index.js", "engines": { @@ -14,9 +14,10 @@ "ingest:test": "mocha test/ingest.test.js --timeout 15000 --exit -r dotenv/config", "ingest:lint": "eslint src", "docker:build": "docker build . -t swr/ard-eventhub", - "docker:clean": "docker rm ard-eventhub", "docker:run": "docker run --env-file .env -p 8080:8080 --name ard-eventhub swr/ard-eventhub", - "license": "chmod +x license.sh && ./license.sh", + "docker:scan": "docker scan node:18-alpine --file=Dockerfile", + "docker:clean": "docker rm ard-eventhub", + "license": "yarn run license-compliance", "test": "mocha test/example.test.js", "reinstall": "rm -rf node_modules && rm yarn.lock && yarn" }, @@ -31,14 +32,14 @@ "@google-cloud/datastore": "^7.0.0", "@google-cloud/pubsub": "^3.1.0", "@google-cloud/secret-manager": "^4.0.0", - "@swrlab/utils": "^1.0.0", + "@swrlab/utils": "^1.0.1", "compression": "^1.7.4", - "dd-trace": "^2.12.1", + "dd-trace": "^2.13.0", "dotenv": "^16.0.1", "express": "4.18.1", "express-openapi-validator": "^4.13.8", "firebase-admin": "^11.0.1", - "google-auth-library": "^8.1.1", + "google-auth-library": "^8.3.0", "jsonwebtoken": "^8.5.1", "moment": "^2.29.4", "slug": "^5.3.0", @@ -48,11 +49,11 @@ }, "devDependencies": { "@swrlab/eslint-plugin-swr": "^0.2.0", - "@swrlab/swr-prettier-config": "^0.1.2", + "@swrlab/swr-prettier-config": "^0.2.0", "chai": "^4.3.6", "chai-http": "^4.3.0", "docsify-cli": "^4.4.4", - "eslint": "^8.21.0", + "eslint": "^8.22.0", "eslint-plugin-chai-friendly": "^0.7.2", "license-compliance": "^1.2.4", "mocha": "^10.0.0", diff --git a/yarn.lock b/yarn.lock index 655f3853..6d4fb96c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -56,18 +56,18 @@ minimist "^1.2.6" tar "^6.1.11" -"@datadog/native-metrics@^1.4.1": - version "1.4.1" - resolved "https://registry.yarnpkg.com/@datadog/native-metrics/-/native-metrics-1.4.1.tgz#fd7cda7de4384632c29eae1210a7cfb0a6a61410" - integrity sha512-YodThqbAHayz+8kuHrtqLF+Qa7BBfawNsW7jla4X6BvKHa310nYzhOfQNWmr7aTOajk7eeF1OqCcxT87E5rIzw== +"@datadog/native-metrics@^1.4.2": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@datadog/native-metrics/-/native-metrics-1.4.2.tgz#ca0c3cedcf56acc468a68c0e44e49d6c90430980" + integrity sha512-ExSIZCEo3pXTNQRuyQllIa+0pc2bVDOntlx0JMnu7+GjeEjJxGyVLw8tTx5EQUmHSLt0Jm7aeMW63C8DJnO27A== dependencies: nan "^2.15.0" node-gyp-build "^3.9.0" -"@datadog/pprof@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@datadog/pprof/-/pprof-1.0.0.tgz#a91bf1c5b3e53e9d49e26bdb1eeacda0b10adb2a" - integrity sha512-m4i45xvMFxmubsGi7NNYZ4VdwZ4bd9S6JXc6GZYvUMmJWkg4YnFkd6kre/El1nHvI1jXozxNuBOPEJHqNxxWYA== +"@datadog/pprof@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@datadog/pprof/-/pprof-1.0.2.tgz#835b2e8596738348a5ba81e5e399cdf3bc85bd35" + integrity sha512-AMTK55W3Aa2QX2X8mN9SQfDGw3HvwIK9Or8pXQFss+kjtH5pCkO9oqE5838MeXgRh9BR8HWrjAQE3Ji7FRCK2g== dependencies: delay "^5.0.0" findit2 "^2.2.3" @@ -81,12 +81,10 @@ source-map "^0.7.3" split "^1.0.1" -"@datadog/sketches-js@^1.0.5": - version "1.0.5" - resolved "https://registry.yarnpkg.com/@datadog/sketches-js/-/sketches-js-1.0.5.tgz#e3202c14e98c5e3aa530944aa03534ccbb9cafaf" - integrity sha512-1ZKyHxxgDI+zY0r+7msMUhFdLR7gkRgKGcNLdYjtXVyo5H64q16J/Khfp5+YAXOedKizKzT0Jf0kLwQ/IBU/pA== - dependencies: - protobufjs "^6.11.3" +"@datadog/sketches-js@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@datadog/sketches-js/-/sketches-js-2.0.0.tgz#621a83b1e0b7d5a4c2e496d6d0194aac0ddd5cd1" + integrity sha512-cR9r5sGYU64HLUe7vRvWuZO8qFrCPWanB/a2nrPPW5E7JVwt5j9QCEjhtPZo6LoImfVr3SajcbmyGwZfFLsHjw== "@eslint/eslintrc@^1.3.0": version "1.3.0" @@ -303,10 +301,10 @@ teeny-request "^8.0.0" uuid "^8.0.0" -"@google-cloud/storage@^6.2.3": - version "6.2.3" - resolved "https://registry.yarnpkg.com/@google-cloud/storage/-/storage-6.2.3.tgz#e3dae8708488cf2e0e4fbf0488083d9d279ee097" - integrity sha512-UJqn3Ln8wFBPLuwBaNu3PlhzQDL3EKKfP1+3mzLRQhcFqgpBSMPLDgAXxc6e9S0l0kqsi4GOuAA7fA+l/VAMjQ== +"@google-cloud/storage@^6.3.0": + version "6.4.1" + resolved "https://registry.yarnpkg.com/@google-cloud/storage/-/storage-6.4.1.tgz#83334150d4e224cb48691de4d7f9c38e143a0970" + integrity sha512-lAddmRJ8tvxPykUqJfONBQA5XGwGk0vut1POXublc64+nCdB5aQMxwuBMf7J1zubx19QGpYPQwW6wR7YTWrvLw== dependencies: "@google-cloud/paginator" "^3.0.7" "@google-cloud/projectify" "^3.0.0" @@ -323,9 +321,7 @@ mime "^3.0.0" mime-types "^2.0.8" p-limit "^3.0.1" - pumpify "^2.0.0" retry-request "^5.0.0" - stream-events "^1.0.4" teeny-request "^8.0.0" uuid "^8.0.0" @@ -510,22 +506,22 @@ eslint-plugin-unicorn "^43.0.2" eslint-plugin-vue "^9.3.0" -"@swrlab/swr-prettier-config@^0.1.2": - version "0.1.2" - resolved "https://registry.yarnpkg.com/@swrlab/swr-prettier-config/-/swr-prettier-config-0.1.2.tgz#e7fd79f72ceeb05a8b631ecc12a2bcae6ae2386b" - integrity sha512-MyUTKRzzvQPexXINH7ASW9dDPtE/OrFfz6UngwyNMpPjAfUu+zJKCzNpiEagUxLGU/8s76oRHqDz5jsN2vyaHw== +"@swrlab/swr-prettier-config@^0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@swrlab/swr-prettier-config/-/swr-prettier-config-0.2.0.tgz#cc3918fca31f3760ba7dad5dd11a3e0440fa623a" + integrity sha512-tq4rM0wq/s30etZOanWrbcHaTbsAIPr/LuedHAvErAiaLdWOJcRIiQjfzfgt9H28UKzrPlSJLiSiufC+zorNDQ== -"@swrlab/utils@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@swrlab/utils/-/utils-1.0.0.tgz#c004d007354c993a8d0ef3328ec82c1cd841b0dd" - integrity sha512-yVHOk8xbBtMbasXY8QIBQfk6x959zTCIBqXfQUHbEG24v6ud5jF4gpueD+LaZT8vbm3tEQ6F+5R6swnWYWvJig== +"@swrlab/utils@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@swrlab/utils/-/utils-1.0.1.tgz#f80175a9496ead2fb1eba511d3492db739f011bd" + integrity sha512-RTwBq4QborqRCmFvbO2rW6JXWkbUPcA/LTaZ0YqIR0u8SLdIgIOzaKyTOAZd19mgfQiwCQjht8nwFMxbkni4Kg== dependencies: - "@google-cloud/storage" "^6.2.3" + "@google-cloud/storage" "^6.3.0" abort-controller "^3.0.0" - aws-sdk "^2.1182.0" + aws-sdk "^2.1190.0" chai "^4.3.6" node-crc swrlab/node-crc#v2.0.15 - undici "^5.8.0" + undici "^5.8.2" uuid "8.3.2" "@szmarczak/http-timer@^4.0.5": @@ -884,10 +880,10 @@ available-typed-arrays@^1.0.5: resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== -aws-sdk@^2.1182.0: - version "2.1182.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1182.0.tgz#7364e3e104f62b61018a00f19f2ffc989b1780ed" - integrity sha512-iemVvLTc2iy0rz3xTp8zc/kD27gIfDF/mk6bxY8/35xMulKCVANWUkAH8jWRKReHh5F/gX4bp33dnfG63ny1Ww== +aws-sdk@^2.1190.0: + version "2.1199.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1199.0.tgz#1279a2086c34232a450f032543fd43e98e3d8232" + integrity sha512-N51EMTCMsiVAJDSKCDTMUheLBlPZ7/c/qyCMGirdoF64/JU+gvZ/u+UqkYPhK7XE80b0GqTj676rtp9OkU1kyg== dependencies: buffer "4.9.2" events "1.1.1" @@ -1437,15 +1433,15 @@ cssesc@^3.0.0: resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== -dd-trace@^2.12.1: - version "2.12.1" - resolved "https://registry.yarnpkg.com/dd-trace/-/dd-trace-2.12.1.tgz#375f95ea3f6f66372a12feb59c518f1d4e5a7c26" - integrity sha512-cokux/Q6WYxyDJIuEeS7epkpWHVB/ay8vijH+xTz9MuRu7qyGJ71RyQGE1EPebgCbrhjekNTE0iEMnD+d/ddug== +dd-trace@^2.13.0: + version "2.13.0" + resolved "https://registry.yarnpkg.com/dd-trace/-/dd-trace-2.13.0.tgz#afd7bd775bac34ffd9464e54ac6a701a14834b89" + integrity sha512-oy98vzQPYYWyNI63cy7DWpbQdhShvrkDkaWztDE+YFpNVKEfRiRXHYtVtyYOuXxEH5RNtcyck5IZuwfxSEOaeA== dependencies: "@datadog/native-appsec" "^1.2.1" - "@datadog/native-metrics" "^1.4.1" - "@datadog/pprof" "^1.0.0" - "@datadog/sketches-js" "^1.0.5" + "@datadog/native-metrics" "^1.4.2" + "@datadog/pprof" "^1.0.2" + "@datadog/sketches-js" "^2.0.0" "@types/node" ">=12" crypto-randomuuid "^1.0.0" diagnostics_channel "^1.1.0" @@ -1461,7 +1457,6 @@ dd-trace@^2.12.1: module-details-from-path "^1.0.3" opentracing ">=0.12.1" path-to-regexp "^0.1.2" - performance-now "^2.1.0" retry "^0.10.1" semver "^5.5.0" @@ -1932,10 +1927,10 @@ eslint-visitor-keys@^3.3.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== -eslint@^8.21.0: - version "8.21.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.21.0.tgz#1940a68d7e0573cef6f50037addee295ff9be9ef" - integrity sha512-/XJ1+Qurf1T9G2M5IHrsjp+xrGT73RZf23xA1z5wB1ZzzEAWSZKvRwhWxTFp1rvkvCfwcvAUNAP31bhKTTGfDA== +eslint@^8.22.0: + version "8.22.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.22.0.tgz#78fcb044196dfa7eef30a9d65944f6f980402c48" + integrity sha512-ci4t0sz6vSRKdmkOGmprBo6fmI4PrphDFMy5JEq/fNS0gQkJM3rLmrqcp8ipMcdobH3KtUP40KniAE9W19S4wA== dependencies: "@eslint/eslintrc" "^1.3.0" "@humanwhocodes/config-array" "^0.10.4" @@ -2515,10 +2510,10 @@ google-auth-library@^8.0.1, google-auth-library@^8.0.2: jws "^4.0.0" lru-cache "^6.0.0" -google-auth-library@^8.1.1: - version "8.1.1" - resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-8.1.1.tgz#4068d2b1512b812d3d3dfbdc848452a0d5a550de" - integrity sha512-eG3pCfrLgVJe19KhAeZwW0m1LplNEo0FX1GboWf3hu18zD2jq8TUH2K8900AB2YRAuJ7A+1aSXDp1BODjwwRzg== +google-auth-library@^8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-8.3.0.tgz#9286a613ee089f1d1728c07b9a302a22acf2dc2a" + integrity sha512-rXasaUScggvyD5ELpQC7SIOUOdqyOIifCK9TRDOLFEcuw1JxuyewKAwDs2QiKzMf8uLa0L360W0bVlV+sJDc8g== dependencies: arrify "^2.0.0" base64-js "^1.3.0" @@ -4065,11 +4060,6 @@ pathval@^1.1.1: resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== - picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" @@ -5017,10 +5007,10 @@ undefsafe@^2.0.5: resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c" integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA== -undici@^5.8.0: - version "5.8.0" - resolved "https://registry.yarnpkg.com/undici/-/undici-5.8.0.tgz#dec9a8ccd90e5a1d81d43c0eab6503146d649a4f" - integrity sha512-1F7Vtcez5w/LwH2G2tGnFIihuWUlc58YidwLiCv+jR2Z50x0tNXpRRw7eOIJ+GvqCqIkg9SB7NWAJ/T9TLfv8Q== +undici@^5.8.2: + version "5.9.1" + resolved "https://registry.yarnpkg.com/undici/-/undici-5.9.1.tgz#fc9fd85dd488f965f153314a63d9426a11f3360b" + integrity sha512-6fB3a+SNnWEm4CJbgo0/CWR8RGcOCQP68SF4X0mxtYTq2VNN8T88NYrWVBAeSX+zb7bny2dx2iYhP3XHi00omg== unique-string@^2.0.0: version "2.0.0"