diff --git a/.github/workflows/check-broken-links-github-github.yml b/.github/workflows/check-broken-links-github-github.yml
index a0561737f78a..d7273d7b20c1 100644
--- a/.github/workflows/check-broken-links-github-github.yml
+++ b/.github/workflows/check-broken-links-github-github.yml
@@ -57,8 +57,11 @@ jobs:
env:
NODE_ENV: production
PORT: 4000
+ # Overload protection is on by default (when NODE_ENV==production)
+ # but it would help in this context.
DISABLE_OVERLOAD_PROTECTION: true
- DISABLE_RENDER_CACHING: true
+ # Render caching won't help when we visit every page exactly once.
+ DISABLE_RENDERING_CACHE: true
run: |
node server.mjs &
diff --git a/.github/workflows/sync-search-indices.yml b/.github/workflows/sync-search-indices.yml
index d2f323733580..51e0975f7414 100644
--- a/.github/workflows/sync-search-indices.yml
+++ b/.github/workflows/sync-search-indices.yml
@@ -92,6 +92,8 @@ jobs:
# Because the overload protection runs in NODE_ENV==production
# and it can break the sync-search.
DISABLE_OVERLOAD_PROTECTION: true
+ # Render caching won't help when we visit every page exactly once.
+ DISABLE_RENDERING_CACHE: true
run: npm run sync-search
diff --git a/components/DefaultLayout.tsx b/components/DefaultLayout.tsx
index 5b89132791fa..311503617695 100644
--- a/components/DefaultLayout.tsx
+++ b/components/DefaultLayout.tsx
@@ -27,6 +27,7 @@ export const DefaultLayout = (props: Props) => {
const { t } = useTranslation(['errors', 'meta', 'scroll_button'])
const router = useRouter()
const metaDescription = page.introPlainText ? page.introPlainText : t('default_description')
+
return (
diff --git a/components/context/DotComAuthenticatedContext.tsx b/components/context/DotComAuthenticatedContext.tsx
new file mode 100644
index 000000000000..fcdf071355a5
--- /dev/null
+++ b/components/context/DotComAuthenticatedContext.tsx
@@ -0,0 +1,19 @@
+import { createContext, useContext } from 'react'
+
+export type DotComAuthenticatedContextT = {
+ isDotComAuthenticated: boolean
+}
+
+export const DotComAuthenticatedContext = createContext(null)
+
+export const useAuth = (): DotComAuthenticatedContextT => {
+ const context = useContext(DotComAuthenticatedContext)
+
+ if (!context) {
+ throw new Error(
+ '"useAuthContext" may only be used inside "DotComAuthenticatedContext.Provider"'
+ )
+ }
+
+ return context
+}
diff --git a/components/context/LanguagesContext.tsx b/components/context/LanguagesContext.tsx
index 748b59031a27..03f2abf18a06 100644
--- a/components/context/LanguagesContext.tsx
+++ b/components/context/LanguagesContext.tsx
@@ -10,6 +10,7 @@ type LanguageItem = {
export type LanguagesContextT = {
languages: Record
+ userLanguage: string
}
export const LanguagesContext = createContext(null)
diff --git a/components/context/MainContext.tsx b/components/context/MainContext.tsx
index 59755e479750..cb10230c1c49 100644
--- a/components/context/MainContext.tsx
+++ b/components/context/MainContext.tsx
@@ -93,7 +93,6 @@ export type MainContextT = {
relativePath?: string
enterpriseServerReleases: EnterpriseServerReleases
currentPathWithoutLanguage: string
- userLanguage: string
allVersions: Record
currentVersion?: string
currentProductTree?: ProductTreeNode | null
@@ -125,7 +124,6 @@ export type MainContextT = {
status: number
fullUrl: string
- isDotComAuthenticated: boolean
}
export const getMainContext = (req: any, res: any): MainContextT => {
@@ -181,7 +179,6 @@ export const getMainContext = (req: any, res: any): MainContextT => {
'supported',
]),
enterpriseServerVersions: req.context.enterpriseServerVersions,
- userLanguage: req.context.userLanguage || '',
allVersions: req.context.allVersions,
currentVersion: req.context.currentVersion,
currentProductTree: req.context.currentProductTree
@@ -192,7 +189,6 @@ export const getMainContext = (req: any, res: any): MainContextT => {
nonEnterpriseDefaultVersion: req.context.nonEnterpriseDefaultVersion,
status: res.statusCode,
fullUrl: req.protocol + '://' + req.get('host') + req.originalUrl,
- isDotComAuthenticated: Boolean(req.cookies.dotcom_user),
}
}
diff --git a/components/page-header/Header.tsx b/components/page-header/Header.tsx
index ddbdc2ede7c1..b0ca9a6bab00 100644
--- a/components/page-header/Header.tsx
+++ b/components/page-header/Header.tsx
@@ -6,6 +6,7 @@ import { useVersion } from 'components/hooks/useVersion'
import { Link } from 'components/Link'
import { useMainContext } from 'components/context/MainContext'
+import { useAuth } from 'components/context/DotComAuthenticatedContext'
import { LanguagePicker } from './LanguagePicker'
import { HeaderNotifications } from 'components/page-header/HeaderNotifications'
import { ProductPicker } from 'components/page-header/ProductPicker'
@@ -17,7 +18,7 @@ import styles from './Header.module.scss'
export const Header = () => {
const router = useRouter()
- const { isDotComAuthenticated, error } = useMainContext()
+ const { error } = useMainContext()
const { currentVersion } = useVersion()
const { t } = useTranslation(['header', 'homepage'])
const [isMenuOpen, setIsMenuOpen] = useState(
@@ -25,6 +26,8 @@ export const Header = () => {
)
const [scroll, setScroll] = useState(false)
+ const { isDotComAuthenticated } = useAuth()
+
const signupCTAVisible =
!isDotComAuthenticated &&
(currentVersion === 'free-pro-team@latest' || currentVersion === 'enterprise-cloud@latest')
diff --git a/components/page-header/HeaderNotifications.tsx b/components/page-header/HeaderNotifications.tsx
index 4b696bc5f61e..0c5dd4d5f033 100644
--- a/components/page-header/HeaderNotifications.tsx
+++ b/components/page-header/HeaderNotifications.tsx
@@ -21,9 +21,9 @@ type Notif = {
export const HeaderNotifications = () => {
const router = useRouter()
const { currentVersion } = useVersion()
- const { relativePath, allVersions, data, userLanguage, currentPathWithoutLanguage, page } =
- useMainContext()
- const { languages } = useLanguages()
+ const { relativePath, allVersions, data, currentPathWithoutLanguage, page } = useMainContext()
+ const { languages, userLanguage } = useLanguages()
+
const { t } = useTranslation('header')
const translationNotices: Array = []
diff --git a/lib/get-theme.js b/lib/get-theme.js
index 50a6e0d181c9..a4b9b964dcae 100644
--- a/lib/get-theme.js
+++ b/lib/get-theme.js
@@ -1,11 +1,9 @@
-// export const defaultCSSThemeProps = {
export const defaultCSSTheme = {
colorMode: 'auto', // light, dark, auto
nightTheme: 'dark',
dayTheme: 'light',
}
-// export const defaultComponentThemeProps = {
export const defaultComponentTheme = {
colorMode: 'auto', // day, night, auto
nightTheme: 'dark',
diff --git a/lib/page.js b/lib/page.js
index eacb1ae9683a..1bc8f7b950cc 100644
--- a/lib/page.js
+++ b/lib/page.js
@@ -24,22 +24,6 @@ import { union } from 'lodash-es'
// every single time, we turn it into a Set once.
const productMapKeysAsSet = new Set(Object.keys(productMap))
-// Wrapper on renderContent() that caches the output depending on the
-// `context` by extracting information about the page's current permalink
-const _renderContentCache = new Map()
-
-function renderContentCacheByContext(prefix) {
- return async function (template = '', context = {}, options = {}) {
- const { currentPath } = context
- const cacheKey = prefix + currentPath
-
- if (!_renderContentCache.has(cacheKey)) {
- _renderContentCache.set(cacheKey, await renderContent(template, context, options))
- }
- return _renderContentCache.get(cacheKey)
- }
-}
-
class Page {
static async init(opts) {
opts = await Page.read(opts)
@@ -186,18 +170,18 @@ class Page {
context.englishHeadings = englishHeadings
}
- this.intro = await renderContentCacheByContext('intro')(this.rawIntro, context)
- this.introPlainText = await renderContentCacheByContext('rawIntro')(this.rawIntro, context, {
+ this.intro = await renderContent(this.rawIntro, context)
+ this.introPlainText = await renderContent(this.rawIntro, context, {
textOnly: true,
})
- this.title = await renderContentCacheByContext('rawTitle')(this.rawTitle, context, {
+ this.title = await renderContent(this.rawTitle, context, {
textOnly: true,
encodeEntities: true,
})
- this.titlePlainText = await renderContentCacheByContext('titleText')(this.rawTitle, context, {
+ this.titlePlainText = await renderContent(this.rawTitle, context, {
textOnly: true,
})
- this.shortTitle = await renderContentCacheByContext('shortTitle')(this.shortTitle, context, {
+ this.shortTitle = await renderContent(this.shortTitle, context, {
textOnly: true,
encodeEntities: true,
})
@@ -205,7 +189,7 @@ class Page {
this.product_video = await renderContent(this.raw_product_video, context, { textOnly: true })
context.relativePath = this.relativePath
- const html = await renderContentCacheByContext('markdown')(this.markdown, context)
+ const html = await renderContent(this.markdown, context)
// Adding communityRedirect for Discussions, Sponsors, and Codespaces - request from Product
if (
@@ -222,15 +206,12 @@ class Page {
// product frontmatter may contain liquid
if (this.rawProduct) {
- this.product = await renderContentCacheByContext('product')(this.rawProduct, context)
+ this.product = await renderContent(this.rawProduct, context)
}
// permissions frontmatter may contain liquid
if (this.rawPermissions) {
- this.permissions = await renderContentCacheByContext('permissions')(
- this.rawPermissions,
- context
- )
+ this.permissions = await renderContent(this.rawPermissions, context)
}
// Learning tracks may contain Liquid and need to have versioning processed.
diff --git a/middleware/cache-full-rendering.js b/middleware/cache-full-rendering.js
new file mode 100644
index 000000000000..0a80b5b70a36
--- /dev/null
+++ b/middleware/cache-full-rendering.js
@@ -0,0 +1,167 @@
+import zlib from 'zlib'
+
+import cheerio from 'cheerio'
+import QuickLRU from 'quick-lru'
+
+// This is what NextJS uses when it injects the JSON serialized
+// in the `
+ //
+ const primerData = $('script#__PRIMER_DATA__')
+ console.assert(primerData.length === 1, 'Not exactly 1')
+ const parsedPrimerData = JSON.parse(primerData.get()[0].children[0].data)
+ parsedPrimerData.resolvedServerColorMode = cssTheme.colorMode === 'dark' ? 'night' : 'day'
+ primerData.text(htmlEscapeJsonString(JSON.stringify(parsedPrimerData)))
+}
diff --git a/middleware/index.js b/middleware/index.js
index 2767f8d4bbed..3c6a2754d39a 100644
--- a/middleware/index.js
+++ b/middleware/index.js
@@ -63,6 +63,7 @@ import assetPreprocessing from './asset-preprocessing.js'
import archivedAssetRedirects from './archived-asset-redirects.js'
import favicons from './favicons.js'
import setStaticAssetCaching from './static-asset-caching.js'
+import cacheFullRendering from './cache-full-rendering.js'
import protect from './overload-protection.js'
import fastHead from './fast-head.js'
@@ -317,6 +318,10 @@ export default function (app) {
// full page rendering.
app.head('/*', fastHead)
+ // For performance, this is before contextualizers if, on a cache hit,
+ // we can't reuse a rendered response without having to contextualize.
+ app.get('/*', asyncMiddleware(instrument(cacheFullRendering, './cache-full-rendering')))
+
// *** Preparation for render-page: contextualizers ***
app.use(asyncMiddleware(instrument(releaseNotes, './contextualizers/release-notes')))
app.use(instrument(graphQL, './contextualizers/graphql'))
diff --git a/middleware/render-page.js b/middleware/render-page.js
index 36919a5ed8a4..f24a2cdf673f 100644
--- a/middleware/render-page.js
+++ b/middleware/render-page.js
@@ -67,7 +67,7 @@ export default async function renderPage(req, res, next) {
// Just finish fast without all the details like Content-Length
if (req.method === 'HEAD') {
- return res.status(200).end()
+ return res.status(200).send('')
}
// Updating the Last-Modified header for substantive changes on a page for engineering
diff --git a/next.config.js b/next.config.js
index c2a44f89d8a0..9ab2fa2ff0b4 100644
--- a/next.config.js
+++ b/next.config.js
@@ -39,4 +39,7 @@ module.exports = {
config.experiments.topLevelAwait = true
return config
},
+
+ // https://nextjs.org/docs/api-reference/next.config.js/compression
+ compress: false,
}
diff --git a/package-lock.json b/package-lock.json
index 3337f44814a0..b65201b8f7be 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -60,6 +60,7 @@
"overload-protection": "^1.2.3",
"parse5": "^6.0.1",
"port-used": "^2.0.8",
+ "quick-lru": "6.1.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-markdown": "^8.0.0",
@@ -4100,48 +4101,6 @@
"once": "^1.4.0"
}
},
- "node_modules/@octokit/request/node_modules/node-fetch": {
- "version": "2.6.7",
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
- "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
- "dev": true,
- "dependencies": {
- "whatwg-url": "^5.0.0"
- },
- "engines": {
- "node": "4.x || >=6.0.0"
- },
- "peerDependencies": {
- "encoding": "^0.1.0"
- },
- "peerDependenciesMeta": {
- "encoding": {
- "optional": true
- }
- }
- },
- "node_modules/@octokit/request/node_modules/tr46": {
- "version": "0.0.3",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
- "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=",
- "dev": true
- },
- "node_modules/@octokit/request/node_modules/webidl-conversions": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
- "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=",
- "dev": true
- },
- "node_modules/@octokit/request/node_modules/whatwg-url": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
- "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
- "dev": true,
- "dependencies": {
- "tr46": "~0.0.3",
- "webidl-conversions": "^3.0.0"
- }
- },
"node_modules/@octokit/rest": {
"version": "18.12.0",
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.12.0.tgz",
@@ -4786,9 +4745,9 @@
"devOptional": true
},
"node_modules/@types/yauzl": {
- "version": "2.9.2",
- "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.2.tgz",
- "integrity": "sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA==",
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz",
+ "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==",
"optional": true,
"dependencies": {
"@types/node": "*"
@@ -5274,7 +5233,7 @@
"node_modules/array-uniq": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
- "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=",
+ "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==",
"optional": true,
"engines": {
"node": ">=0.10.0"
@@ -6420,7 +6379,7 @@
"node_modules/bfj": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/bfj/-/bfj-4.2.4.tgz",
- "integrity": "sha1-hfeyNoPCr9wVhgOEotHD+sgO0zo=",
+ "integrity": "sha512-+c08z3TYqv4dy9b0MAchQsxYlzX9D2asHWW4VhO4ZFTnK7v9ps6iNhEQLqJyEZS6x9G0pgOCk/L7B9E4kp8glQ==",
"optional": true,
"dependencies": {
"check-types": "^7.3.0",
@@ -6467,7 +6426,7 @@
"node_modules/bmp-js": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz",
- "integrity": "sha1-4Fpj95amwf8l9Hcex62twUjAcjM=",
+ "integrity": "sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw==",
"optional": true
},
"node_modules/bn.js": {
@@ -6792,7 +6751,7 @@
"node_modules/buffer-crc32": {
"version": "0.2.13",
"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
- "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=",
+ "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
"optional": true,
"engines": {
"node": "*"
@@ -6801,7 +6760,7 @@
"node_modules/buffer-equal": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz",
- "integrity": "sha1-kbx0sR6kBbyRa8aqkI+q+ltKrEs=",
+ "integrity": "sha512-RgSV6InVQ9ODPdLWJ5UAqBqJBOg370Nz6ZQtRzpt6nUjc8v0St97uJ4PYC6NztqIScrAXafKM3mZPMygSe1ggA==",
"optional": true,
"engines": {
"node": ">=0.4.0"
@@ -6928,6 +6887,18 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/camelcase-keys/node_modules/quick-lru": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
+ "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/camelcase-keys/node_modules/type-fest": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz",
@@ -8745,16 +8716,6 @@
"node": ">= 0.8.0"
}
},
- "node_modules/escodegen/node_modules/source-map": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
- "dev": true,
- "optional": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/escodegen/node_modules/type-check": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
@@ -10221,9 +10182,9 @@
}
},
"node_modules/fs-extra": {
- "version": "10.0.1",
- "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz",
- "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==",
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
+ "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
"optional": true,
"dependencies": {
"graceful-fs": "^4.2.0",
@@ -10249,19 +10210,6 @@
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"devOptional": true
},
- "node_modules/fsevents": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
- "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
- "hasInstallScript": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
- }
- },
"node_modules/function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
@@ -10289,48 +10237,6 @@
"node": ">=10"
}
},
- "node_modules/gaxios/node_modules/node-fetch": {
- "version": "2.6.7",
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
- "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
- "dev": true,
- "dependencies": {
- "whatwg-url": "^5.0.0"
- },
- "engines": {
- "node": "4.x || >=6.0.0"
- },
- "peerDependencies": {
- "encoding": "^0.1.0"
- },
- "peerDependenciesMeta": {
- "encoding": {
- "optional": true
- }
- }
- },
- "node_modules/gaxios/node_modules/tr46": {
- "version": "0.0.3",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
- "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=",
- "dev": true
- },
- "node_modules/gaxios/node_modules/webidl-conversions": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
- "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=",
- "dev": true
- },
- "node_modules/gaxios/node_modules/whatwg-url": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
- "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
- "dev": true,
- "dependencies": {
- "tr46": "~0.0.3",
- "webidl-conversions": "^3.0.0"
- }
- },
"node_modules/gemoji": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/gemoji/-/gemoji-4.2.1.tgz",
@@ -10419,12 +10325,12 @@
"dev": true
},
"node_modules/gifwrap": {
- "version": "0.9.2",
- "resolved": "https://registry.npmjs.org/gifwrap/-/gifwrap-0.9.2.tgz",
- "integrity": "sha512-fcIswrPaiCDAyO8xnWvHSZdWChjKXUanKKpAiWWJ/UTkEi/aYKn5+90e7DE820zbEaVR9CE2y4z9bzhQijZ0BA==",
+ "version": "0.9.4",
+ "resolved": "https://registry.npmjs.org/gifwrap/-/gifwrap-0.9.4.tgz",
+ "integrity": "sha512-MDMwbhASQuVeD4JKd1fKgNgCRL3fGqMM4WaqpNhWO0JiMOAjbQdumbs4BbBZEy9/M00EHEjKN3HieVhCUlwjeQ==",
"optional": true,
"dependencies": {
- "image-q": "^1.1.1",
+ "image-q": "^4.0.0",
"omggif": "^1.0.10"
}
},
@@ -11367,6 +11273,17 @@
"node": ">=10.19.0"
}
},
+ "node_modules/http2-wrapper/node_modules/quick-lru": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
+ "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/https-browserify": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",
@@ -11455,14 +11372,20 @@
"dev": true
},
"node_modules/image-q": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/image-q/-/image-q-1.1.1.tgz",
- "integrity": "sha1-/IQJlmRGC5DKhi2TALa/u7+/gFY=",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/image-q/-/image-q-4.0.0.tgz",
+ "integrity": "sha512-PfJGVgIfKQJuq3s0tTDOKtztksibuUEbJQIYT3by6wctQo+Rdlh7ef4evJ5NCdxY4CfMbvFkocEwbl4BF8RlJw==",
"optional": true,
- "engines": {
- "node": ">=0.9.0"
+ "dependencies": {
+ "@types/node": "16.9.1"
}
},
+ "node_modules/image-q/node_modules/@types/node": {
+ "version": "16.9.1",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.1.tgz",
+ "integrity": "sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==",
+ "optional": true
+ },
"node_modules/image-size": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/image-size/-/image-size-1.0.0.tgz",
@@ -15761,25 +15684,6 @@
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
- "node_modules/next/node_modules/node-fetch": {
- "version": "2.6.7",
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
- "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
- "dependencies": {
- "whatwg-url": "^5.0.0"
- },
- "engines": {
- "node": "4.x || >=6.0.0"
- },
- "peerDependencies": {
- "encoding": "^0.1.0"
- },
- "peerDependenciesMeta": {
- "encoding": {
- "optional": true
- }
- }
- },
"node_modules/next/node_modules/node-releases": {
"version": "1.1.77",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.77.tgz",
@@ -15843,11 +15747,6 @@
"node": ">=4"
}
},
- "node_modules/next/node_modules/tr46": {
- "version": "0.0.3",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
- "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
- },
"node_modules/next/node_modules/watchpack": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.1.1.tgz",
@@ -15860,20 +15759,6 @@
"node": ">=10.13.0"
}
},
- "node_modules/next/node_modules/webidl-conversions": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
- "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
- },
- "node_modules/next/node_modules/whatwg-url": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
- "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
- "dependencies": {
- "tr46": "~0.0.3",
- "webidl-conversions": "^3.0.0"
- }
- },
"node_modules/no-case": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
@@ -15899,6 +15784,44 @@
"node": ">= 10.13"
}
},
+ "node_modules/node-fetch": {
+ "version": "2.6.7",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
+ "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
+ "dependencies": {
+ "whatwg-url": "^5.0.0"
+ },
+ "engines": {
+ "node": "4.x || >=6.0.0"
+ },
+ "peerDependencies": {
+ "encoding": "^0.1.0"
+ },
+ "peerDependenciesMeta": {
+ "encoding": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/node-fetch/node_modules/tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
+ },
+ "node_modules/node-fetch/node_modules/webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
+ },
+ "node_modules/node-fetch/node_modules/whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
+ "dependencies": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ },
"node_modules/node-html-parser": {
"version": "1.4.9",
"resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-1.4.9.tgz",
@@ -16669,7 +16592,7 @@
"node_modules/pa11y-ci/node_modules/ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
- "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
"optional": true,
"engines": {
"node": ">=0.10.0"
@@ -16678,7 +16601,7 @@
"node_modules/pa11y-ci/node_modules/ansi-styles": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==",
"optional": true,
"engines": {
"node": ">=0.10.0"
@@ -16687,7 +16610,7 @@
"node_modules/pa11y-ci/node_modules/array-union": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
- "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
+ "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==",
"optional": true,
"dependencies": {
"array-uniq": "^1.0.1"
@@ -16709,7 +16632,7 @@
"node_modules/pa11y-ci/node_modules/chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==",
"optional": true,
"dependencies": {
"ansi-styles": "^2.2.1",
@@ -16768,15 +16691,15 @@
"optional": true
},
"node_modules/pa11y-ci/node_modules/glob": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
- "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"optional": true,
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
- "minimatch": "^3.0.4",
+ "minimatch": "^3.1.1",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
@@ -16849,30 +16772,11 @@
"mkdirp": "bin/cmd.js"
}
},
- "node_modules/pa11y-ci/node_modules/node-fetch": {
- "version": "2.6.7",
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
- "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
- "optional": true,
- "dependencies": {
- "whatwg-url": "^5.0.0"
- },
- "engines": {
- "node": "4.x || >=6.0.0"
- },
- "peerDependencies": {
- "encoding": "^0.1.0"
- },
- "peerDependenciesMeta": {
- "encoding": {
- "optional": true
- }
- }
- },
"node_modules/pa11y-ci/node_modules/puppeteer": {
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-1.19.0.tgz",
"integrity": "sha512-2S6E6ygpoqcECaagDbBopoSOPDv0pAZvTbnBgUY+6hq0/XDFDOLEMNlHF/SKJlzcaZ9ckiKjKDuueWI3FN/WXw==",
+ "deprecated": "Version no longer supported. Upgrade to @latest",
"hasInstallScript": true,
"optional": true,
"dependencies": {
@@ -16922,28 +16826,6 @@
"node": ">=0.8.0"
}
},
- "node_modules/pa11y-ci/node_modules/tr46": {
- "version": "0.0.3",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
- "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=",
- "optional": true
- },
- "node_modules/pa11y-ci/node_modules/webidl-conversions": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
- "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=",
- "optional": true
- },
- "node_modules/pa11y-ci/node_modules/whatwg-url": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
- "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
- "optional": true,
- "dependencies": {
- "tr46": "~0.0.3",
- "webidl-conversions": "^3.0.0"
- }
- },
"node_modules/pa11y-ci/node_modules/ws": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz",
@@ -16957,6 +16839,7 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/pa11y-reporter-cli/-/pa11y-reporter-cli-1.0.1.tgz",
"integrity": "sha512-k+XPl5pBU2R1J6iagGv/GpN/dP7z2cX9WXqO0ALpBwHlHN3ZSukcHCOhuLMmkOZNvufwsvobaF5mnaZxT70YyA==",
+ "deprecated": "This package is now bundled with pa11y. You can find the latest version of this package in the pa11y repo.",
"optional": true,
"dependencies": {
"chalk": "^2.1.0"
@@ -17040,6 +16923,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/pa11y-reporter-csv/-/pa11y-reporter-csv-1.0.0.tgz",
"integrity": "sha512-S2gFgbAvONBzAVsVbF8zsYabszrzj7SKhQxrEbw19zF0OFI8wCWn8dFywujYYkg674rmyjweSxSdD+kHTcx4qA==",
+ "deprecated": "This package is now bundled with pa11y. You can find the latest version of this package in the pa11y repo.",
"optional": true,
"engines": {
"node": ">=8"
@@ -17049,6 +16933,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/pa11y-reporter-json/-/pa11y-reporter-json-1.0.0.tgz",
"integrity": "sha512-EdLrzh1hyZ8DudCSSrcakgtsHDiSsYNsWLSoEAo1JnFTIK8hYpD7vL+xgd0u+LXDxz9wLLFnckdubpklaRpl/w==",
+ "deprecated": "This package is now bundled with pa11y. You can find the latest version of this package in the pa11y repo.",
"optional": true,
"dependencies": {
"bfj": "^4.2.3"
@@ -17061,6 +16946,7 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/pa11y-runner-axe/-/pa11y-runner-axe-1.0.2.tgz",
"integrity": "sha512-HMw5kQZz16vS5Bhe067esgeuULNzFYP4ixOFAHxOurwGDptlyc2OqH6zfUuK4szB9tbgb5F23v3qz9hCbkGRpw==",
+ "deprecated": "This package is now bundled with pa11y. You can find the latest version of this package in the pa11y repo.",
"optional": true,
"dependencies": {
"axe-core": "^3.5.1"
@@ -17082,6 +16968,7 @@
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/pa11y-runner-htmlcs/-/pa11y-runner-htmlcs-1.2.1.tgz",
"integrity": "sha512-flatSp6moEbqzny18b2IEoDXEWj6xJbJrszdBjUAPQBCN11QRW+SZ0U4uFnxNTLPpXs30N/a9IlH4vYiRr2nPg==",
+ "deprecated": "This package is now bundled with pa11y. You can find the latest version of this package in the pa11y repo.",
"optional": true,
"dependencies": {
"html_codesniffer": "~2.4.1"
@@ -17149,15 +17036,15 @@
"optional": true
},
"node_modules/pa11y/node_modules/glob": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
- "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"optional": true,
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
- "minimatch": "^3.0.4",
+ "minimatch": "^3.1.1",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
@@ -17218,6 +17105,7 @@
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-1.19.0.tgz",
"integrity": "sha512-2S6E6ygpoqcECaagDbBopoSOPDv0pAZvTbnBgUY+6hq0/XDFDOLEMNlHF/SKJlzcaZ9ckiKjKDuueWI3FN/WXw==",
+ "deprecated": "Version no longer supported. Upgrade to @latest",
"hasInstallScript": true,
"optional": true,
"dependencies": {
@@ -17527,9 +17415,9 @@
}
},
"node_modules/parse-headers": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.3.tgz",
- "integrity": "sha512-QhhZ+DCCit2Coi2vmAKbq5RGTRcQUOE2+REgv8vdyu7MnYx2eZztegqtTx99TZ86GTIwqiy3+4nQTWZ2tgmdCA==",
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz",
+ "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==",
"optional": true
},
"node_modules/parse-json": {
@@ -18137,6 +18025,7 @@
"version": "9.1.1",
"resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-9.1.1.tgz",
"integrity": "sha512-W+nOulP2tYd/ZG99WuZC/I5ljjQQ7EUw/jQGcIb9eu8mDlZxNY2SgcJXTLG9h5gRvqA3uJOe4hZXYsd3EqioMw==",
+ "deprecated": "Version no longer supported. Upgrade to @latest",
"hasInstallScript": true,
"optional": true,
"dependencies": {
@@ -18157,48 +18046,6 @@
"node": ">=10.18.1"
}
},
- "node_modules/puppeteer/node_modules/node-fetch": {
- "version": "2.6.7",
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
- "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
- "optional": true,
- "dependencies": {
- "whatwg-url": "^5.0.0"
- },
- "engines": {
- "node": "4.x || >=6.0.0"
- },
- "peerDependencies": {
- "encoding": "^0.1.0"
- },
- "peerDependenciesMeta": {
- "encoding": {
- "optional": true
- }
- }
- },
- "node_modules/puppeteer/node_modules/tr46": {
- "version": "0.0.3",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
- "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=",
- "optional": true
- },
- "node_modules/puppeteer/node_modules/webidl-conversions": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
- "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=",
- "optional": true
- },
- "node_modules/puppeteer/node_modules/whatwg-url": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
- "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
- "optional": true,
- "dependencies": {
- "tr46": "~0.0.3",
- "webidl-conversions": "^3.0.0"
- }
- },
"node_modules/qs": {
"version": "6.9.6",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz",
@@ -18256,11 +18103,11 @@
]
},
"node_modules/quick-lru": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
- "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-6.1.0.tgz",
+ "integrity": "sha512-8HdyR8c0jNVWbYrhUWs9Tg/qAAHgjuJoOIX+mP3eIhgqPO9ytMRURCEFTkOxaHLLsEXo0Cm+bXO5ULuGez+45g==",
"engines": {
- "node": ">=10"
+ "node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -22474,9 +22321,9 @@
}
},
"node_modules/website-scraper/node_modules/got": {
- "version": "12.0.3",
- "resolved": "https://registry.npmjs.org/got/-/got-12.0.3.tgz",
- "integrity": "sha512-hmdcXi/S0gcAtDg4P8j/rM7+j3o1Aq6bXhjxkDhRY2ipe7PHpvx/14DgTY2czHOLaGeU8VRvRecidwfu9qdFug==",
+ "version": "12.0.4",
+ "resolved": "https://registry.npmjs.org/got/-/got-12.0.4.tgz",
+ "integrity": "sha512-2Eyz4iU/ktq7wtMFXxzK7g5p35uNYLLdiZarZ5/Yn3IJlNEpBd5+dCgcAyxN8/8guZLszffwe3wVyw+DEVrpBg==",
"optional": true,
"dependencies": {
"@sindresorhus/is": "^4.6.0",
@@ -22501,9 +22348,9 @@
}
},
"node_modules/website-scraper/node_modules/http2-wrapper": {
- "version": "2.1.10",
- "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.1.10.tgz",
- "integrity": "sha512-QHgsdYkieKp+6JbXP25P+tepqiHYd+FVnDwXpxi/BlUcoIB0nsmTOymTNvETuTO+pDuwcSklPE72VR3DqV+Haw==",
+ "version": "2.1.11",
+ "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.1.11.tgz",
+ "integrity": "sha512-aNAk5JzLturWEUiuhAN73Jcbq96R7rTitAoXV54FYMatvihnpD2+6PUgU4ce3D/m5VDbw+F5CsyKSF176ptitQ==",
"optional": true,
"dependencies": {
"quick-lru": "^5.1.1",
@@ -22546,6 +22393,18 @@
"node": ">=12.20"
}
},
+ "node_modules/website-scraper/node_modules/quick-lru": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
+ "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
+ "optional": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/whatwg-encoding": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz",
@@ -25836,39 +25695,6 @@
"is-plain-object": "^5.0.0",
"node-fetch": "^2.6.1",
"universal-user-agent": "^6.0.0"
- },
- "dependencies": {
- "node-fetch": {
- "version": "2.6.7",
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
- "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
- "dev": true,
- "requires": {
- "whatwg-url": "^5.0.0"
- }
- },
- "tr46": {
- "version": "0.0.3",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
- "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=",
- "dev": true
- },
- "webidl-conversions": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
- "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=",
- "dev": true
- },
- "whatwg-url": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
- "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
- "dev": true,
- "requires": {
- "tr46": "~0.0.3",
- "webidl-conversions": "^3.0.0"
- }
- }
}
},
"@octokit/request-error": {
@@ -26491,9 +26317,9 @@
"devOptional": true
},
"@types/yauzl": {
- "version": "2.9.2",
- "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.2.tgz",
- "integrity": "sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA==",
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz",
+ "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==",
"optional": true,
"requires": {
"@types/node": "*"
@@ -26816,7 +26642,7 @@
"array-uniq": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
- "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=",
+ "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==",
"optional": true
},
"array.prototype.flat": {
@@ -27839,7 +27665,7 @@
"bfj": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/bfj/-/bfj-4.2.4.tgz",
- "integrity": "sha1-hfeyNoPCr9wVhgOEotHD+sgO0zo=",
+ "integrity": "sha512-+c08z3TYqv4dy9b0MAchQsxYlzX9D2asHWW4VhO4ZFTnK7v9ps6iNhEQLqJyEZS6x9G0pgOCk/L7B9E4kp8glQ==",
"optional": true,
"requires": {
"check-types": "^7.3.0",
@@ -27877,7 +27703,7 @@
"bmp-js": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz",
- "integrity": "sha1-4Fpj95amwf8l9Hcex62twUjAcjM=",
+ "integrity": "sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw==",
"optional": true
},
"bn.js": {
@@ -28131,13 +27957,13 @@
"buffer-crc32": {
"version": "0.2.13",
"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
- "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=",
+ "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
"optional": true
},
"buffer-equal": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz",
- "integrity": "sha1-kbx0sR6kBbyRa8aqkI+q+ltKrEs=",
+ "integrity": "sha512-RgSV6InVQ9ODPdLWJ5UAqBqJBOg370Nz6ZQtRzpt6nUjc8v0St97uJ4PYC6NztqIScrAXafKM3mZPMygSe1ggA==",
"optional": true
},
"buffer-from": {
@@ -28234,6 +28060,12 @@
"integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
"dev": true
},
+ "quick-lru": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
+ "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
+ "dev": true
+ },
"type-fest": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz",
@@ -29648,13 +29480,6 @@
"integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
"dev": true
},
- "source-map": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
- "dev": true,
- "optional": true
- },
"type-check": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
@@ -30767,9 +30592,9 @@
"devOptional": true
},
"fs-extra": {
- "version": "10.0.1",
- "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz",
- "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==",
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
+ "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
"optional": true,
"requires": {
"graceful-fs": "^4.2.0",
@@ -30791,12 +30616,6 @@
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"devOptional": true
},
- "fsevents": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
- "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
- "optional": true
- },
"function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
@@ -30819,39 +30638,6 @@
"https-proxy-agent": "^5.0.0",
"is-stream": "^2.0.0",
"node-fetch": "^2.6.1"
- },
- "dependencies": {
- "node-fetch": {
- "version": "2.6.7",
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
- "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
- "dev": true,
- "requires": {
- "whatwg-url": "^5.0.0"
- }
- },
- "tr46": {
- "version": "0.0.3",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
- "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=",
- "dev": true
- },
- "webidl-conversions": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
- "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=",
- "dev": true
- },
- "whatwg-url": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
- "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
- "dev": true,
- "requires": {
- "tr46": "~0.0.3",
- "webidl-conversions": "^3.0.0"
- }
- }
}
},
"gemoji": {
@@ -30918,12 +30704,12 @@
"dev": true
},
"gifwrap": {
- "version": "0.9.2",
- "resolved": "https://registry.npmjs.org/gifwrap/-/gifwrap-0.9.2.tgz",
- "integrity": "sha512-fcIswrPaiCDAyO8xnWvHSZdWChjKXUanKKpAiWWJ/UTkEi/aYKn5+90e7DE820zbEaVR9CE2y4z9bzhQijZ0BA==",
+ "version": "0.9.4",
+ "resolved": "https://registry.npmjs.org/gifwrap/-/gifwrap-0.9.4.tgz",
+ "integrity": "sha512-MDMwbhASQuVeD4JKd1fKgNgCRL3fGqMM4WaqpNhWO0JiMOAjbQdumbs4BbBZEy9/M00EHEjKN3HieVhCUlwjeQ==",
"optional": true,
"requires": {
- "image-q": "^1.1.1",
+ "image-q": "^4.0.0",
"omggif": "^1.0.10"
}
},
@@ -31644,6 +31430,13 @@
"requires": {
"quick-lru": "^5.1.1",
"resolve-alpn": "^1.0.0"
+ },
+ "dependencies": {
+ "quick-lru": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
+ "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA=="
+ }
}
},
"https-browserify": {
@@ -31699,10 +31492,21 @@
"dev": true
},
"image-q": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/image-q/-/image-q-1.1.1.tgz",
- "integrity": "sha1-/IQJlmRGC5DKhi2TALa/u7+/gFY=",
- "optional": true
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/image-q/-/image-q-4.0.0.tgz",
+ "integrity": "sha512-PfJGVgIfKQJuq3s0tTDOKtztksibuUEbJQIYT3by6wctQo+Rdlh7ef4evJ5NCdxY4CfMbvFkocEwbl4BF8RlJw==",
+ "optional": true,
+ "requires": {
+ "@types/node": "16.9.1"
+ },
+ "dependencies": {
+ "@types/node": {
+ "version": "16.9.1",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.1.tgz",
+ "integrity": "sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==",
+ "optional": true
+ }
+ }
},
"image-size": {
"version": "1.0.0",
@@ -34824,14 +34628,6 @@
}
}
},
- "node-fetch": {
- "version": "2.6.7",
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
- "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
- "requires": {
- "whatwg-url": "^5.0.0"
- }
- },
"node-releases": {
"version": "1.1.77",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.77.tgz",
@@ -34878,11 +34674,6 @@
}
}
},
- "tr46": {
- "version": "0.0.3",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
- "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
- },
"watchpack": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.1.1.tgz",
@@ -34891,20 +34682,6 @@
"glob-to-regexp": "^0.4.1",
"graceful-fs": "^4.1.2"
}
- },
- "webidl-conversions": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
- "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
- },
- "whatwg-url": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
- "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
- "requires": {
- "tr46": "~0.0.3",
- "webidl-conversions": "^3.0.0"
- }
}
}
},
@@ -34930,6 +34707,35 @@
"propagate": "^2.0.0"
}
},
+ "node-fetch": {
+ "version": "2.6.7",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
+ "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
+ "requires": {
+ "whatwg-url": "^5.0.0"
+ },
+ "dependencies": {
+ "tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
+ },
+ "webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
+ },
+ "whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
+ "requires": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ }
+ }
+ },
"node-html-parser": {
"version": "1.4.9",
"resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-1.4.9.tgz",
@@ -35554,15 +35360,15 @@
}
},
"glob": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
- "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"optional": true,
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
- "minimatch": "^3.0.4",
+ "minimatch": "^3.1.1",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
@@ -35679,19 +35485,19 @@
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
- "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
"optional": true
},
"ansi-styles": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==",
"optional": true
},
"array-union": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
- "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
+ "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==",
"optional": true,
"requires": {
"array-uniq": "^1.0.1"
@@ -35710,7 +35516,7 @@
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==",
"optional": true,
"requires": {
"ansi-styles": "^2.2.1",
@@ -35762,15 +35568,15 @@
}
},
"glob": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
- "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"optional": true,
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
- "minimatch": "^3.0.4",
+ "minimatch": "^3.1.1",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
@@ -35827,15 +35633,6 @@
"minimist": "^1.2.6"
}
},
- "node-fetch": {
- "version": "2.6.7",
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
- "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
- "optional": true,
- "requires": {
- "whatwg-url": "^5.0.0"
- }
- },
"puppeteer": {
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-1.19.0.tgz",
@@ -35876,28 +35673,6 @@
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
"optional": true
},
- "tr46": {
- "version": "0.0.3",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
- "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=",
- "optional": true
- },
- "webidl-conversions": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
- "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=",
- "optional": true
- },
- "whatwg-url": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
- "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
- "optional": true,
- "requires": {
- "tr46": "~0.0.3",
- "webidl-conversions": "^3.0.0"
- }
- },
"ws": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz",
@@ -36240,9 +36015,9 @@
}
},
"parse-headers": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.3.tgz",
- "integrity": "sha512-QhhZ+DCCit2Coi2vmAKbq5RGTRcQUOE2+REgv8vdyu7MnYx2eZztegqtTx99TZ86GTIwqiy3+4nQTWZ2tgmdCA==",
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz",
+ "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==",
"optional": true
},
"parse-json": {
@@ -36728,39 +36503,6 @@
"tar-fs": "^2.0.0",
"unbzip2-stream": "^1.3.3",
"ws": "^7.2.3"
- },
- "dependencies": {
- "node-fetch": {
- "version": "2.6.7",
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
- "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
- "optional": true,
- "requires": {
- "whatwg-url": "^5.0.0"
- }
- },
- "tr46": {
- "version": "0.0.3",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
- "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=",
- "optional": true
- },
- "webidl-conversions": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
- "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=",
- "optional": true
- },
- "whatwg-url": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
- "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
- "optional": true,
- "requires": {
- "tr46": "~0.0.3",
- "webidl-conversions": "^3.0.0"
- }
- }
}
},
"qs": {
@@ -36793,9 +36535,9 @@
"dev": true
},
"quick-lru": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
- "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA=="
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-6.1.0.tgz",
+ "integrity": "sha512-8HdyR8c0jNVWbYrhUWs9Tg/qAAHgjuJoOIX+mP3eIhgqPO9ytMRURCEFTkOxaHLLsEXo0Cm+bXO5ULuGez+45g=="
},
"random-bytes": {
"version": "1.0.0",
@@ -40026,9 +39768,9 @@
"optional": true
},
"got": {
- "version": "12.0.3",
- "resolved": "https://registry.npmjs.org/got/-/got-12.0.3.tgz",
- "integrity": "sha512-hmdcXi/S0gcAtDg4P8j/rM7+j3o1Aq6bXhjxkDhRY2ipe7PHpvx/14DgTY2czHOLaGeU8VRvRecidwfu9qdFug==",
+ "version": "12.0.4",
+ "resolved": "https://registry.npmjs.org/got/-/got-12.0.4.tgz",
+ "integrity": "sha512-2Eyz4iU/ktq7wtMFXxzK7g5p35uNYLLdiZarZ5/Yn3IJlNEpBd5+dCgcAyxN8/8guZLszffwe3wVyw+DEVrpBg==",
"optional": true,
"requires": {
"@sindresorhus/is": "^4.6.0",
@@ -40047,9 +39789,9 @@
}
},
"http2-wrapper": {
- "version": "2.1.10",
- "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.1.10.tgz",
- "integrity": "sha512-QHgsdYkieKp+6JbXP25P+tepqiHYd+FVnDwXpxi/BlUcoIB0nsmTOymTNvETuTO+pDuwcSklPE72VR3DqV+Haw==",
+ "version": "2.1.11",
+ "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.1.11.tgz",
+ "integrity": "sha512-aNAk5JzLturWEUiuhAN73Jcbq96R7rTitAoXV54FYMatvihnpD2+6PUgU4ce3D/m5VDbw+F5CsyKSF176ptitQ==",
"optional": true,
"requires": {
"quick-lru": "^5.1.1",
@@ -40073,6 +39815,12 @@
"resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz",
"integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==",
"optional": true
+ },
+ "quick-lru": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
+ "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
+ "optional": true
}
}
},
diff --git a/package.json b/package.json
index 354a8996f88e..2920614ef9ac 100644
--- a/package.json
+++ b/package.json
@@ -62,6 +62,7 @@
"overload-protection": "^1.2.3",
"parse5": "^6.0.1",
"port-used": "^2.0.8",
+ "quick-lru": "6.1.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-markdown": "^8.0.0",
diff --git a/pages/_app.tsx b/pages/_app.tsx
index eab4108e8211..27494db15fcd 100644
--- a/pages/_app.tsx
+++ b/pages/_app.tsx
@@ -10,14 +10,27 @@ import '../stylesheets/index.scss'
import events from 'components/lib/events'
import experiment from 'components/lib/experiment'
import { LanguagesContext, LanguagesContextT } from 'components/context/LanguagesContext'
+import {
+ DotComAuthenticatedContext,
+ DotComAuthenticatedContextT,
+} from 'components/context/DotComAuthenticatedContext'
import { defaultComponentTheme } from 'lib/get-theme.js'
type MyAppProps = AppProps & {
csrfToken: string
+ isDotComAuthenticated: boolean
themeProps: typeof defaultComponentTheme & Pick
languagesContext: LanguagesContextT
+ dotComAuthenticatedContext: DotComAuthenticatedContextT
}
-const MyApp = ({ Component, pageProps, csrfToken, themeProps, languagesContext }: MyAppProps) => {
+const MyApp = ({
+ Component,
+ pageProps,
+ csrfToken,
+ themeProps,
+ languagesContext,
+ dotComAuthenticatedContext,
+}: MyAppProps) => {
useEffect(() => {
events()
experiment()
@@ -58,7 +71,9 @@ const MyApp = ({ Component, pageProps, csrfToken, themeProps, languagesContext }
preventSSRMismatch
>
-
+
+
+
@@ -66,6 +81,10 @@ const MyApp = ({ Component, pageProps, csrfToken, themeProps, languagesContext }
)
}
+// Remember, function is only called once if the rendered page can
+// be in-memory cached. But still, the `` component will be
+// executed every time **in the client** if it was the first time
+// ever (since restart) or from a cached HTML.
MyApp.getInitialProps = async (appContext: AppContext) => {
const { ctx } = appContext
// calls page's `getInitialProps` and fills `appProps.pageProps`
@@ -78,7 +97,8 @@ MyApp.getInitialProps = async (appContext: AppContext) => {
...appProps,
themeProps: getTheme(req),
csrfToken: req?.csrfToken?.() || '',
- languagesContext: { languages: req.context.languages },
+ languagesContext: { languages: req.context.languages, userLanguage: req.context.userLanguage },
+ dotComAuthenticatedContext: { isDotComAuthenticated: Boolean(req.cookies?.dotcom_user) },
}
}
diff --git a/script/search/sync.js b/script/search/sync.js
index 81d995118eda..cde5e3014713 100644
--- a/script/search/sync.js
+++ b/script/search/sync.js
@@ -11,6 +11,7 @@ import LunrIndex from './lunr-search-index.js'
// Build a search data file for every combination of product version and language
// e.g. `github-docs-dotcom-en.json` and `github-docs-2.14-ja.json`
export default async function syncSearchIndexes(opts = {}) {
+ const t0 = new Date()
if (opts.language) {
if (!Object.keys(languages).includes(opts.language)) {
console.log(
@@ -89,6 +90,9 @@ export default async function syncSearchIndexes(opts = {}) {
}
}
}
+ const t1 = new Date()
+ const tookSec = (t1.getTime() - t0.getTime()) / 1000
console.log('\nDone!')
+ console.log(`Took ${tookSec.toFixed(1)} seconds`)
}
diff --git a/tests/helpers/script-data.js b/tests/helpers/script-data.js
new file mode 100644
index 000000000000..fd4887edb878
--- /dev/null
+++ b/tests/helpers/script-data.js
@@ -0,0 +1,29 @@
+const NEXT_DATA_QUERY = 'script#__NEXT_DATA__'
+const PRIMER_DATA_QUERY = 'script#__PRIMER_DATA__'
+
+function getScriptData($, key) {
+ const data = $(key)
+ if (!data.length === 1) {
+ throw new Error(`Not exactly 1 element match for '${key}'. Found ${data.length}`)
+ }
+ return JSON.parse(data.get()[0].children[0].data)
+}
+
+export const getNextData = ($) => getScriptData($, NEXT_DATA_QUERY)
+export const getPrimerData = ($) => getScriptData($, PRIMER_DATA_QUERY)
+
+export const getUserLanguage = ($) => {
+ // Because the page might come from the middleware rendering cache,
+ // the DOM won't get updated until the first client-side React render.
+ // But we can assert the data that would be used for that first render.
+ const { props } = getNextData($)
+ return props.languagesContext.userLanguage
+}
+
+export const getIsDotComAuthenticated = ($) => {
+ // Because the page might come from the middleware rendering cache,
+ // the DOM won't get updated until the first client-side React render.
+ // But we can assert the data that would be used for that first render.
+ const { props } = getNextData($)
+ return props.dotComAuthenticatedContext.isDotComAuthenticated
+}
diff --git a/tests/rendering/head.js b/tests/rendering/head.js
index 1a117d8c6012..111ca523caaa 100644
--- a/tests/rendering/head.js
+++ b/tests/rendering/head.js
@@ -13,7 +13,16 @@ describe('', () => {
expect($hreflangs.length).toEqual(Object.keys(languages).length)
expect($('link[href="https://docs.github.com/cn"]').length).toBe(1)
expect($('link[href="https://docs.github.com/ja"]').length).toBe(1)
- expect($('link[hrefLang="en"]').length).toBe(1)
+ // Due to a bug in either NextJS, JSX, or TypeScript,
+ // when put `` in a .tsx file, this incorrectly
+ // gets rendered out as `` in the final HTML.
+ // Note the uppercase L. It's supposed to become ``.
+ // When cheerio serializes to HTML, it gets this right so it lowercases
+ // the attribute. So if this rendering in this jest test was the first
+ // ever cold hit, you might get the buggy HTML from React or you
+ // might get the correct HTML from cheerio's `.html()` serializer.
+ // This is why we're looking for either.
+ expect($('link[hreflang="en"]').length + $('link[hrefLang="en"]').length).toBe(1)
})
test('includes page intro in `description` meta tag', async () => {
diff --git a/tests/rendering/header.js b/tests/rendering/header.js
index 78c223a31d6e..221c15ac219a 100644
--- a/tests/rendering/header.js
+++ b/tests/rendering/header.js
@@ -1,7 +1,8 @@
-import { jest } from '@jest/globals'
+import { expect, jest } from '@jest/globals'
import { getDOM } from '../helpers/e2etest.js'
import { oldestSupported } from '../../lib/enterprise-server-releases.js'
+import { getUserLanguage } from '../helpers/script-data.js'
describe('header', () => {
jest.setTimeout(5 * 60 * 1000)
@@ -91,54 +92,31 @@ describe('header', () => {
test("renders a link to the same page in user's preferred language, if available", async () => {
const headers = { 'accept-language': 'ja' }
const $ = await getDOM('/en', { headers })
- expect($('[data-testid=header-notification][data-type=TRANSLATION]').length).toBe(1)
- expect($('[data-testid=header-notification] a[href*="/ja"]').length).toBe(1)
+ expect(getUserLanguage($)).toBe('ja')
})
test("renders a link to the same page if user's preferred language is Chinese - PRC", async () => {
const headers = { 'accept-language': 'zh-CN' }
const $ = await getDOM('/en', { headers })
- expect($('[data-testid=header-notification][data-type=TRANSLATION]').length).toBe(1)
- expect($('[data-testid=header-notification] a[href*="/cn"]').length).toBe(1)
- })
-
- test("does not render a link when user's preferred language is Chinese - Taiwan", async () => {
- const headers = { 'accept-language': 'zh-TW' }
- const $ = await getDOM('/en', { headers })
- expect($('[data-testid=header-notification]').length).toBe(0)
- })
-
- test("does not render a link when user's preferred language is English", async () => {
- const headers = { 'accept-language': 'en' }
- const $ = await getDOM('/en', { headers })
- expect($('[data-testid=header-notification]').length).toBe(0)
+ expect(getUserLanguage($)).toBe('cn')
})
test("renders a link to the same page in user's preferred language from multiple, if available", async () => {
const headers = { 'accept-language': 'ja, *;q=0.9' }
const $ = await getDOM('/en', { headers })
- expect($('[data-testid=header-notification][data-type=TRANSLATION]').length).toBe(1)
- expect($('[data-testid=header-notification] a[href*="/ja"]').length).toBe(1)
+ expect(getUserLanguage($)).toBe('ja')
})
test("renders a link to the same page in user's preferred language with weights, if available", async () => {
const headers = { 'accept-language': 'ja;q=1.0, *;q=0.9' }
const $ = await getDOM('/en', { headers })
- expect($('[data-testid=header-notification][data-type=TRANSLATION]').length).toBe(1)
- expect($('[data-testid=header-notification] a[href*="/ja"]').length).toBe(1)
+ expect(getUserLanguage($)).toBe('ja')
})
test("renders a link to the user's 2nd preferred language if 1st is not available", async () => {
const headers = { 'accept-language': 'zh-TW,zh;q=0.9,ja *;q=0.8' }
const $ = await getDOM('/en', { headers })
- expect($('[data-testid=header-notification][data-type=TRANSLATION]').length).toBe(1)
- expect($('[data-testid=header-notification] a[href*="/ja"]').length).toBe(1)
- })
-
- test('renders no notices if no language preference is available', async () => {
- const headers = { 'accept-language': 'zh-TW,zh;q=0.9,zh-SG *;q=0.8' }
- const $ = await getDOM('/en', { headers })
- expect($('[data-testid=header-notification]').length).toBe(0)
+ expect(getUserLanguage($)).toBe('ja')
})
})
diff --git a/tests/rendering/render-caching.js b/tests/rendering/render-caching.js
new file mode 100644
index 000000000000..49c0a2442d69
--- /dev/null
+++ b/tests/rendering/render-caching.js
@@ -0,0 +1,160 @@
+import cheerio from 'cheerio'
+import { expect, jest, test } from '@jest/globals'
+
+import { get } from '../helpers/e2etest.js'
+import { PREFERRED_LOCALE_COOKIE_NAME } from '../../middleware/detect-language.js'
+import {
+ getNextData,
+ getPrimerData,
+ getUserLanguage,
+ getIsDotComAuthenticated,
+} from '../helpers/script-data.js'
+
+const serializeTheme = (theme) => {
+ return encodeURIComponent(JSON.stringify(theme))
+}
+
+describe('in-memory render caching', () => {
+ jest.setTimeout(30 * 1000)
+
+ test('second render should be a cache hit with different csrf-token', async () => {
+ const res = await get('/en')
+ // Because these are effectively end-to-end tests, you can't expect
+ // the first request to be a cache miss because another end-to-end
+ // test might have "warmed up" this endpoint.
+ expect(res.headers['x-middleware-cache']).toBeTruthy()
+ const $1 = cheerio.load(res.text)
+ const res2 = await get('/en')
+ expect(res2.headers['x-middleware-cache']).toBe('hit')
+ const $2 = cheerio.load(res2.text)
+ const csrfTokenHTML1 = $1('meta[name="csrf-token"]').attr('content')
+ const csrfTokenHTML2 = $2('meta[name="csrf-token"]').attr('content')
+ expect(csrfTokenHTML1).not.toBe(csrfTokenHTML2)
+ // The HTML is one thing, we also need to check that the
+ // __NEXT_DATA__ serialized (JSON) state is different.
+ const csrfTokenNEXT1 = getNextData($1).props.csrfToken
+ const csrfTokenNEXT2 = getNextData($2).props.csrfToken
+ expect(csrfTokenHTML1).toBe(csrfTokenNEXT1)
+ expect(csrfTokenHTML2).toBe(csrfTokenNEXT2)
+ expect(csrfTokenNEXT1).not.toBe(csrfTokenNEXT2)
+ })
+
+ test('second render should be a cache hit with different dotcom-auth', async () => {
+ // Anonymous first
+ const res = await get('/en')
+ // Because these are effectively end-to-end tests, you can't expect
+ // the first request to be a cache miss because another end-to-end
+ // test might have "warmed up" this endpoint.
+ expect(res.headers['x-middleware-cache']).toBeTruthy()
+ const $1 = cheerio.load(res.text)
+ const res2 = await get('/en', {
+ headers: {
+ cookie: 'dotcom_user=peterbe',
+ },
+ })
+ expect(res2.headers['x-middleware-cache']).toBe('hit')
+ const $2 = cheerio.load(res2.text)
+ // The HTML is one thing, we also need to check that the
+ // __NEXT_DATA__ serialized (JSON) state is different.
+ const dotcomAuthNEXT1 = getIsDotComAuthenticated($1)
+ const dotcomAuthNEXT2 = getIsDotComAuthenticated($2)
+ expect(dotcomAuthNEXT1).not.toBe(dotcomAuthNEXT2)
+ })
+
+ test('second render should be a cache hit with different theme properties', async () => {
+ const cookieValue1 = {
+ color_mode: 'light',
+ light_theme: { name: 'light', color_mode: 'light' },
+ dark_theme: { name: 'dark_high_contrast', color_mode: 'dark' },
+ }
+ // Light mode first
+ const res1 = await get('/en', {
+ headers: {
+ cookie: `color_mode=${serializeTheme(cookieValue1)}`,
+ },
+ })
+ // Because these are effectively end-to-end tests, you can't expect
+ // the first request to be a cache miss because another end-to-end
+ // test might have "warmed up" this endpoint.
+ expect(res1.headers['x-middleware-cache']).toBeTruthy()
+ const $1 = cheerio.load(res1.text)
+ expect($1('body').data('color-mode')).toBe(cookieValue1.color_mode)
+ const themeProps1 = getNextData($1).props.themeProps
+ expect(themeProps1.colorMode).toBe('day')
+
+ const cookieValue2 = {
+ color_mode: 'dark',
+ light_theme: { name: 'light', color_mode: 'light' },
+ dark_theme: { name: 'dark_high_contrast', color_mode: 'dark' },
+ }
+ const res2 = await get('/en', {
+ headers: {
+ cookie: `color_mode=${serializeTheme(cookieValue2)}`,
+ },
+ })
+ expect(res2.headers['x-middleware-cache']).toBeTruthy()
+ const $2 = cheerio.load(res2.text)
+ expect($2('body').data('color-mode')).toBe(cookieValue2.color_mode)
+ const themeProps2 = getNextData($2).props.themeProps
+ expect(themeProps2.colorMode).toBe('night')
+ })
+
+ test('second render should be cache hit with different resolvedServerColorMode in __PRIMER_DATA__', async () => {
+ await get('/en') // first render to assert the next render comes from cache
+
+ const res = await get('/en', {
+ headers: {
+ cookie: `color_mode=${serializeTheme({
+ color_mode: 'dark',
+ light_theme: { name: 'light', color_mode: 'light' },
+ dark_theme: { name: 'dark_high_contrast', color_mode: 'dark' },
+ })}`,
+ },
+ })
+ expect(res.headers['x-middleware-cache']).toBeTruthy()
+ const $ = cheerio.load(res.text)
+ const data = getPrimerData($)
+ expect(data.resolvedServerColorMode).toBe('night')
+
+ // Now do it all over again but with a light color mode
+ const res2 = await get('/en', {
+ headers: {
+ cookie: `color_mode=${serializeTheme({
+ color_mode: 'light',
+ light_theme: { name: 'light', color_mode: 'light' },
+ dark_theme: { name: 'dark_high_contrast', color_mode: 'dark' },
+ })}`,
+ },
+ })
+ expect(res2.headers['x-middleware-cache']).toBeTruthy()
+ const $2 = cheerio.load(res2.text)
+ const data2 = getPrimerData($2)
+ expect(data2.resolvedServerColorMode).toBe('day')
+ })
+
+ test('user-language, by header, in meta tag', async () => {
+ await get('/en') // first render to assert the next render comes from cache
+
+ const res = await get('/en', {
+ headers: { 'accept-language': 'ja;q=1.0, *;q=0.9' },
+ })
+ expect(res.headers['x-middleware-cache']).toBeTruthy()
+ const $ = cheerio.load(res.text)
+ const userLanguage = getUserLanguage($)
+ expect(userLanguage).toBe('ja')
+ })
+
+ test('user-language, by cookie, in meta tag', async () => {
+ await get('/en') // first render to assert the next render comes from cache
+
+ const res = await get('/en', {
+ headers: {
+ Cookie: `${PREFERRED_LOCALE_COOKIE_NAME}=ja`,
+ },
+ })
+ expect(res.headers['x-middleware-cache']).toBeTruthy()
+ const $ = cheerio.load(res.text)
+ const userLanguage = getUserLanguage($)
+ expect(userLanguage).toBe('ja')
+ })
+})
diff --git a/tests/rendering/signup-button.js b/tests/rendering/signup-button.js
index 64881cdab841..673f9521b527 100644
--- a/tests/rendering/signup-button.js
+++ b/tests/rendering/signup-button.js
@@ -1,23 +1,14 @@
import { jest, describe, expect } from '@jest/globals'
import { getDOM } from '../helpers/e2etest.js'
+import { getIsDotComAuthenticated } from '../helpers/script-data.js'
describe('GHEC sign up button', () => {
jest.setTimeout(60 * 1000)
- test('present by default', async () => {
+ test('false by default', async () => {
const $ = await getDOM('/en')
- expect($('a[href^="https://github.com/signup"]').length).toBeGreaterThan(0)
- })
-
- test('present on enterprise-cloud pages', async () => {
- const $ = await getDOM('/en/enterprise-cloud@latest')
- expect($('a[href^="https://github.com/signup"]').length).toBeGreaterThan(0)
- })
-
- test('not present on enterprise-server pages', async () => {
- const $ = await getDOM('/en/enterprise-server@latest')
- expect($('a[href^="https://github.com/signup"]').length).toBe(0)
+ expect(getIsDotComAuthenticated($)).toBe(false)
})
test('not present if dotcom_user cookie', async () => {
@@ -26,6 +17,15 @@ describe('GHEC sign up button', () => {
cookie: 'dotcom_user=peterbe',
},
})
- expect($('a[href^="https://github.com/signup"]').length).toBe(0)
+ expect(getIsDotComAuthenticated($)).toBe(true)
+
+ // Do another request, same URL, but different cookie, just to
+ // make sure the server-side rendering cache isn't failing.
+ const $2 = await getDOM('/en', {
+ headers: {
+ cookie: 'bla=bla',
+ },
+ })
+ expect(getIsDotComAuthenticated($2)).toBe(false)
})
})