diff --git a/.github/workflows/fetch-quickstarts.yml b/.github/workflows/fetch-quickstarts.yml new file mode 100644 index 00000000..8ff8186d --- /dev/null +++ b/.github/workflows/fetch-quickstarts.yml @@ -0,0 +1,103 @@ +name: Fetch Quickstarts + +on: + workflow_dispatch: + schedule: + - cron: '0 1,5,9,13,17,21 * * *' # Every 4 hours staggered by 1 hour + +env: + BOT_NAME: nr-opensource-bot + BOT_EMAIL: opensource+bot@newrelic.com + NODE_OPTIONS: '--max-old-space-size=4096' + +jobs: + fetch-quickstarts: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v2 + with: + ref: main + + - name: Setup node.js + uses: actions/setup-node@v1 + with: + node-version: 16 + + - name: Cache dependencies + id: yarn-cache + uses: actions/cache@v2 + with: + path: '**/node_modules' + key: ${{ runner.os }}-node-modules-${{ hashFiles('**/yarn.lock') }} + + - name: Install dependencies + if: steps.yarn-cache.outputs.cache-hit != 'true' + run: yarn install --frozen-lockfile + + - name: Fetch quickstarts + run: yarn run fetch-quickstarts + env: + NR_API_URL: 'https://api.newrelic.com/graphql' + NR_API_TOKEN: ${{ secrets.NR_API_TOKEN }} + + - name: Temporarily disable branch protection + id: disable-branch-protection + uses: actions/github-script@v1 + with: + github-token: ${{ secrets.OPENSOURCE_BOT_TOKEN }} + previews: luke-cage-preview + script: | + const result = await github.repos.updateBranchProtection({ + owner: context.repo.owner, + repo: context.repo.repo, + branch: 'main', + required_status_checks: null, + restrictions: null, + enforce_admins: null, + required_pull_request_reviews: null + }) + console.log("Result:", result) + + - name: Commit changes + id: commit-changes + run: | + git config --local user.email "${{ env.BOT_EMAIL }}" + git config --local user.name "${{ env.BOT_NAME }}" + git add ./src/data/quickstarts.json + git diff-index --quiet HEAD ./src/data/quickstarts.json || git commit -m 'chore(quickstarts): updated quickstarts' + echo "::set-output name=commit::true" + + - name: Push Commit + if: steps.commit-changes.outputs.commit == 'true' + uses: ad-m/github-push-action@v0.6.0 + with: + github_token: ${{ secrets.OPENSOURCE_BOT_TOKEN }} + branch: main + + - name: Re-enable branch protection + id: enable-branch-protection + if: always() + uses: actions/github-script@v1 + with: + github-token: ${{ secrets.OPENSOURCE_BOT_TOKEN }} + previews: luke-cage-preview + script: | + const result = await github.repos.updateBranchProtection({ + owner: context.repo.owner, + repo: context.repo.repo, + branch: 'main', + required_status_checks: { + strict: false, + contexts: [ + 'Gatsby Build Service - instant-observability-website' + ] + }, + restrictions: null, + enforce_admins: true, + required_pull_request_reviews: { + dismiss_stale_reviews: true, + required_approving_review_count: 1 + } + }) + console.log("Result:", result) diff --git a/gatsby-config.js b/gatsby-config.js index dc695b74..23b63919 100644 --- a/gatsby-config.js +++ b/gatsby-config.js @@ -1,8 +1,31 @@ module.exports = { - siteMetadata: { - siteUrl: `https://www.yourdomain.tld`, + siteMetadata: { + siteUrl: `https://www.yourdomain.tld`, + }, + plugins: [ + { + resolve: "gatsby-source-filesystem", + options: { + name: "quickstarts", + path: `${__dirname}/src/data/quickstarts.json`, + }, }, - plugins: [ + { + resolve: "gatsby-transformer-json", + options: { + // If we need to source json files other than the i18n/nav, we should + // consider making this dynamic. See the docs for ways to do this. + // + // https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-transformer-json + typeName: "Quickstarts", + }, + }, + { + resolve: "gatsby-plugin-gatsby-cloud", + options: { + allPageHeaders: ["Referrer-Policy: no-referrer-when-downgrade"], + }, + }, + ], +}; - ] -} \ No newline at end of file diff --git a/package.json b/package.json index c068b8d9..5deb46ab 100644 --- a/package.json +++ b/package.json @@ -12,10 +12,14 @@ "start": "gatsby develop", "build": "gatsby build", "serve": "gatsby serve", - "clean": "gatsby clean" + "clean": "gatsby clean", + "fetch-quickstarts": "node ./scripts/actions/fetch-quickstarts.js" }, "dependencies": { "gatsby": "^4.5.3", + "gatsby-plugin-gatsby-cloud": "^4.5.2", + "gatsby-source-filesystem": "^4.5.2", + "gatsby-transformer-json": "^4.5.0", "react": "^17.0.1", "react-dom": "^17.0.1" } diff --git a/scripts/actions/__tests__/fetch-quickstarts.test.js b/scripts/actions/__tests__/fetch-quickstarts.test.js new file mode 100644 index 00000000..1f087060 --- /dev/null +++ b/scripts/actions/__tests__/fetch-quickstarts.test.js @@ -0,0 +1,121 @@ +'use strict'; + +const fs = require('fs'); +const fetch = require('node-fetch'); +const fetchQuickstarts = require('../fetch-quickstarts'); + +jest.mock('node-fetch'); +jest.mock('fs'); + +describe('Action: Fetch Observability Packs', () => { + const fakeAPIURL = 'fakeapi.com/graphql'; + const fakeToken = 'fake_token'; + const fakeGqlQuery = 'fake_gql_query'; + + afterEach(() => { + jest.resetAllMocks(); + }); + + test('writes observability packs to file', async () => { + const apiReturnValue = { + data: { + docs: { + openInstallation: { + quickstartSearch: { + results: { + quickstarts: [ + { + test: 'test', + }, + ], + }, + }, + }, + }, + }, + }; + fetch.mockResolvedValueOnce({ + ok: true, + json: jest.fn(() => Promise.resolve(apiReturnValue)), + }); + + await fetchQuickstarts(fakeGqlQuery, fakeAPIURL, fakeToken); + expect(fs.writeFileSync.mock.calls.length).toBe(1); + expect(fs.writeFileSync.mock.calls[0][0]).toStrictEqual( + './src/data/quickstarts.json' + ); + expect(fs.writeFileSync.mock.calls[0][1]).toStrictEqual( + JSON.stringify([{ test: 'test' }], null, 2) + ); + }); + + test('does not write file when graphql errors are returned', async () => { + const apiReturnValue = { + errors: { + testError: 'error', + }, + data: { + docs: { + openInstallation: { + quickstartSearch: { + results: { + quickstarts: [ + { + test: 'test', + }, + ], + }, + }, + }, + }, + }, + }; + fetch.mockResolvedValueOnce({ + json: jest.fn(() => Promise.resolve(apiReturnValue)), + ok: true, + }); + + await fetchQuickstarts(fakeGqlQuery, fakeAPIURL, fakeToken); + expect(fs.writeFileSync).not.toHaveBeenCalled(); + }); + + test('does not write file when graphql response is malformed', async () => { + const apiReturnValue = { + data: { + docs: { + quickstartSearch: { + results: { + quickstarts: [ + { + test: 'test', + }, + ], + }, + }, + }, + }, + }; + fetch.mockResolvedValueOnce({ + json: jest.fn(() => Promise.resolve(apiReturnValue)), + ok: true, + }); + + await fetchQuickstarts(fakeGqlQuery, fakeAPIURL, fakeToken); + expect(fs.writeFileSync).not.toHaveBeenCalled(); + }); + + test('does not write file when a network error occurs', async () => { + fetch.mockImplementation(() => Promise.reject()); + await fetchQuickstarts(fakeGqlQuery, fakeAPIURL, fakeToken); + expect(fs.writeFileSync).not.toHaveBeenCalled(); + }); + + test('does not write file when a non-200 status is returned from the API', async () => { + fetch.mockResolvedValueOnce({ + status: 500, + ok: false, + }); + await fetchQuickstarts(fakeGqlQuery, fakeAPIURL, fakeToken); + expect(fs.writeFileSync).not.toHaveBeenCalled(); + }); +}); diff --git a/scripts/actions/fetch-quickstarts.js b/scripts/actions/fetch-quickstarts.js new file mode 100644 index 00000000..27eb5a80 --- /dev/null +++ b/scripts/actions/fetch-quickstarts.js @@ -0,0 +1,147 @@ +'use strict'; + +/** + * This script is used to query the New Relic GraphQL API for Quickstarts. + * It then writes the array of Quickstarts to src/data/quickstarts.json + * It requires the following environment variables to be set: + * NR_GQL_URL - The New Relic GraphQL URL + * NR_API_TOKEN - A New Relic personal API token + **/ + +/* eslint-disable no-console */ +const fs = require('fs'); +const fetch = require('node-fetch'); +const get = require('lodash.get'); + +const QUICKSTARTS_FILE_PATH = './src/data/quickstarts.json'; +const NR_API_URL = process.env.NR_API_URL; +const NR_API_TOKEN = process.env.NR_API_TOKEN; + +const quickstartQuery = `# gql + { + docs { + openInstallation { + quickstartSearch { + count + results { + quickstarts { + authors + dashboards { + description + name + screenshots + url + } + alerts { + name + details + type + url + } + documentation { + name + description + url + } + description + iconUrl + packUrl + id + title + level + logoUrl + name + summary + websiteUrl + keywords + installPlans { + id + name + } + } + } + } + } + } + } +`; + +/** + * Queries graphql for the provided query + * @param {String} queryString the graphql query to send + * @param {String} url NR graphql endpoint + * @param {String} token NR api token + * @returns {Promise} returns the resulting array + * or `undefined` if there was an error + **/ +const fetchQuickstarts = async (queryString, url, token) => { + try { + const res = await fetch(url, { + method: 'post', + body: JSON.stringify({ query: queryString }), + headers: { + 'Content-Type': 'application/json', + 'Api-Key': token, + }, + }); + + if (!res.ok) { + throw new Error(`Received status code ${res.status} from the API`); + } + + const results = await res.json(); + + if (results.errors) { + throw new Error(JSON.stringify(results.errors, null, 2)); + } + + return get(results, 'data.docs.openInstallation.quickstartSearch.results'); + } catch (error) { + console.error('Encountered a problem querying the graphql api', error); + } +}; + +const validateEnvVars = () => { + if (typeof NR_API_URL !== 'string') { + throw new Error('NR_GQL_URL environment variable not set, exiting...'); + } + + if (typeof NR_API_TOKEN !== 'string') { + throw new Error('NR_API_TOKEN environment variable not set, exiting...'); + } +}; + +/* + * @param {String} query a graphql query for quickstarts + * @param {String} url the New Relic API endpoint + * @param {String} token a New Relic API token + **/ +const main = async (query, url, token) => { + const results = await fetchQuickstarts(query, url, token); + + if (results) { + const quickstarts = results.quickstarts; + console.log(`Found ${quickstarts.length} quickstarts.`); + console.log(`Writing ${QUICKSTARTS_FILE_PATH}`); + fs.writeFileSync( + QUICKSTARTS_FILE_PATH, + JSON.stringify(quickstarts, null, 2) + ); + } else { + console.log( + 'No quickstarts were returned from the api, check the logs for errors.' + ); + if (require.main === module) { + process.exit(1); + } + } +}; + +if (require.main === module) { + validateEnvVars(); + main(quickstartQuery, NR_API_URL, NR_API_TOKEN); +} + +module.exports = main; + +/* eslint-enable no-console */ diff --git a/yarn.lock b/yarn.lock index 899d6b64..1e50400c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2536,7 +2536,7 @@ chalk@^3.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: +chalk@^4.0, chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -3087,7 +3087,7 @@ dataloader@2.0.0: resolved "https://registry.yarnpkg.com/dataloader/-/dataloader-2.0.0.tgz#41eaf123db115987e21ca93c005cd7753c55fe6f" integrity sha512-YzhyDAwA4TaQIhM5go+vCLmU0UikghC/t9DTQYZR2M/UvZ1MdOhPezSDZcjj9uqQJOMqjLcpWtyW2iNINdlatQ== -date-fns@^2.25.0: +date-fns@^2.25.0, date-fns@^2.28.0: version "2.28.0" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.28.0.tgz#9570d656f5fc13143e50c975a3b6bbeb46cd08b2" integrity sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw== @@ -3147,7 +3147,7 @@ deep-is@^0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== -deepmerge@^4.2.2: +deepmerge@^4.0, deepmerge@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== @@ -4356,6 +4356,20 @@ gatsby-page-utils@^2.5.2: lodash "^4.17.21" micromatch "^4.0.4" +gatsby-plugin-gatsby-cloud@^4.5.2: + version "4.5.2" + resolved "https://registry.yarnpkg.com/gatsby-plugin-gatsby-cloud/-/gatsby-plugin-gatsby-cloud-4.5.2.tgz#8ec4fa8cdf296e08a0d4999b755b4626c8532984" + integrity sha512-aloSM+XVuideA7ZIAO1pOBb8pC+QYq873MMDWGPZt1O61ZbtfgEkigzuSbGZqcmrPnJT37n/iia6Q/PC0/YEkA== + dependencies: + "@babel/runtime" "^7.15.4" + date-fns "^2.28.0" + fs-extra "^10.0.0" + gatsby-core-utils "^3.5.2" + gatsby-telemetry "^3.5.2" + kebab-hash "^0.1.2" + lodash "^4.17.21" + webpack-assets-manifest "^5.0.6" + gatsby-plugin-page-creator@^4.5.2: version "4.5.2" resolved "https://registry.yarnpkg.com/gatsby-plugin-page-creator/-/gatsby-plugin-page-creator-4.5.2.tgz#31f58cc7faa50fae8a070d1868ac5cb5594edcba" @@ -4401,6 +4415,25 @@ gatsby-react-router-scroll@^5.5.0: dependencies: "@babel/runtime" "^7.15.4" +gatsby-source-filesystem@^4.5.2: + version "4.5.2" + resolved "https://registry.yarnpkg.com/gatsby-source-filesystem/-/gatsby-source-filesystem-4.5.2.tgz#e139b3beb4afa14cd9211899ab0542091724cc35" + integrity sha512-q3S7ffE3EdxIr3kpqN9UyDOJeHePuc6VLqodibbeEFO/l+DVrmvLSDTQlo2n6MUQtEsQ+UWyitcX2+WydpCGBg== + dependencies: + "@babel/runtime" "^7.15.4" + chokidar "^3.5.2" + fastq "^1.13.0" + file-type "^16.5.3" + fs-extra "^10.0.0" + gatsby-core-utils "^3.5.2" + got "^9.6.0" + md5-file "^5.0.0" + mime "^2.5.2" + pretty-bytes "^5.4.1" + progress "^2.0.3" + valid-url "^1.0.9" + xstate "^4.26.1" + gatsby-telemetry@^3.5.2: version "3.5.2" resolved "https://registry.yarnpkg.com/gatsby-telemetry/-/gatsby-telemetry-3.5.2.tgz#e6434a12e1c88a64078c8af4c9042f2df631f49c" @@ -4420,6 +4453,14 @@ gatsby-telemetry@^3.5.2: lodash "^4.17.21" node-fetch "^2.6.6" +gatsby-transformer-json@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/gatsby-transformer-json/-/gatsby-transformer-json-4.5.0.tgz#276755ff7c106552d19768d69dffefa8fa00234e" + integrity sha512-rJowAiNsxx7uhf2BugljPa/xCRJmAkGRQSacLaGL7ZtePMEmTEpgCgjl/jfSOJvq4f+E1mFH4Z8g1psJ/WEYmQ== + dependencies: + "@babel/runtime" "^7.15.4" + bluebird "^3.7.2" + gatsby-worker@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/gatsby-worker/-/gatsby-worker-1.5.0.tgz#e29c9a6f8d5cc1c5307e3fc483f20ffdb4e0a032" @@ -5645,6 +5686,13 @@ jsonfile@^6.0.1: array-includes "^3.1.3" object.assign "^4.1.2" +kebab-hash@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/kebab-hash/-/kebab-hash-0.1.2.tgz#dfb7949ba34d8e70114ea7d83e266e5e2a4abaac" + integrity sha512-BTZpq3xgISmQmAVzkISy4eUutsUA7s4IEFlCwOBJjvSFOwyR7I+fza+tBc/rzYWK/NrmFHjfU1IhO3lu29Ib/w== + dependencies: + lodash.kebabcase "^4.1.1" + keyv@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" @@ -5801,6 +5849,13 @@ lock@^1.1.0: resolved "https://registry.yarnpkg.com/lock/-/lock-1.1.0.tgz#53157499d1653b136ca66451071fca615703fa55" integrity sha1-UxV0mdFlOxNspmRRBx/KYVcD+lU= +lockfile@^1.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/lockfile/-/lockfile-1.0.4.tgz#07f819d25ae48f87e538e6578b6964a4981a5609" + integrity sha512-cvbTwETRfsFh4nHsL1eGWapU1XFi5Ot9E85sWAwia7Y7EgB7vfqcZhTKZ+l7hCGxSPoushMv5GKhT5PdLv03WA== + dependencies: + signal-exit "^3.0.2" + lodash.clonedeep@4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" @@ -5836,11 +5891,21 @@ lodash.foreach@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53" integrity sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM= -lodash.get@^4: +lodash.get@^4, lodash.get@^4.0: version "4.4.2" resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= +lodash.has@^4.0: + version "4.5.2" + resolved "https://registry.yarnpkg.com/lodash.has/-/lodash.has-4.5.2.tgz#d19f4dc1095058cccbe2b0cdf4ee0fe4aa37c862" + integrity sha1-0Z9NwQlQWMzL4rDN9O4P5Ko3yGI= + +lodash.kebabcase@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36" + integrity sha1-hImxyw0p/4gZXM7KRI/21swpXDY= + lodash.map@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3" @@ -7047,6 +7112,11 @@ prepend-http@^2.0.0: resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= +pretty-bytes@^5.4.1: + version "5.6.0" + resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb" + integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg== + pretty-error@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.2.tgz#be89f82d81b1c86ec8fdfbc385045882727f93b6" @@ -7640,7 +7710,7 @@ schema-utils@^2.6.5: ajv "^6.12.4" ajv-keywords "^3.5.2" -schema-utils@^3.0.0, schema-utils@^3.1.0, schema-utils@^3.1.1: +schema-utils@^3.0, schema-utils@^3.0.0, schema-utils@^3.1.0, schema-utils@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281" integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw== @@ -8249,7 +8319,7 @@ tapable@^1.0.0: resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== -tapable@^2.1.1, tapable@^2.2.0: +tapable@^2.0, tapable@^2.1.1, tapable@^2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== @@ -8660,7 +8730,7 @@ v8-compile-cache@^2.0.3, v8-compile-cache@^2.3.0: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== -valid-url@1.0.9: +valid-url@1.0.9, valid-url@^1.0.9: version "1.0.9" resolved "https://registry.yarnpkg.com/valid-url/-/valid-url-1.0.9.tgz#1c14479b40f1397a75782f115e4086447433a200" integrity sha1-HBRHm0DxOXp1eC8RXkCGRHQzogA= @@ -8698,6 +8768,19 @@ webidl-conversions@^3.0.0: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= +webpack-assets-manifest@^5.0.6: + version "5.1.0" + resolved "https://registry.yarnpkg.com/webpack-assets-manifest/-/webpack-assets-manifest-5.1.0.tgz#5af328f6c8fa760cb9a62af631a83da2b478b791" + integrity sha512-kPuTMEjBrqZQVJ5M6yXNBCEdFbQQn7p+loNXt8NOeDFaAbsNFWqqwR0YL1mfG5LbwhK5FLXWXpuK3GuIIZ46rg== + dependencies: + chalk "^4.0" + deepmerge "^4.0" + lockfile "^1.0" + lodash.get "^4.0" + lodash.has "^4.0" + schema-utils "^3.0" + tapable "^2.0" + webpack-dev-middleware@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-4.3.0.tgz#179cc40795882cae510b1aa7f3710cbe93c9333e" @@ -8901,7 +8984,7 @@ xss@^1.0.6: commander "^2.20.3" cssfilter "0.0.10" -xstate@^4.26.0: +xstate@^4.26.0, xstate@^4.26.1: version "4.28.0" resolved "https://registry.yarnpkg.com/xstate/-/xstate-4.28.0.tgz#e5802638120951793ef7ea5a91e975f86244a73c" integrity sha512-qavuFNzejRZVR75Pmbc7zOuUvVOWoABn6sucHr9M5oWjP3LeJ8A5T9lYfADiaY0o9E6q1T63f6JIhCBgt4XTdw==