feat: social features

This commit is contained in:
Travis Fischer
2021-01-17 18:54:52 -05:00
parent a4084000c8
commit 04fe54e00b
17 changed files with 423 additions and 101 deletions

View File

@@ -13,9 +13,5 @@ GCLOUD_PROJECT=
FIREBASE_COLLECTION_IMAGES=
DOMAIN=
NOTION_ROOT_PAGE_ID=
# Optional
#FATHOM_ID=

1
.gitignore vendored
View File

@@ -25,6 +25,7 @@ yarn-debug.log*
yarn-error.log*
# local env files
.env
.env.local
.env.development.local
.env.test.local

View File

@@ -14,8 +14,16 @@ import { NotionRenderer } from 'react-notion-x'
import { getBlockTitle } from 'notion-utils'
import * as types from 'lib/types'
import { mapPageUrl, getCanonicalPageUrl } from 'lib/map-page-url'
import { mapNotionImageUrl } from 'lib/map-image-url'
import { isDev } from 'lib/config'
import { mapImageUrl, mapNotionImageUrl } from 'lib/map-image-url'
import { getPageDescription } from 'lib/get-page-description'
import {
isDev,
api,
siteDescription,
defaultPageCover,
defaultPageCoverPosition,
defaultPageIcon
} from 'lib/config'
import { searchNotion } from 'lib/search-notion'
// components
@@ -89,10 +97,15 @@ export const NotionPage: React.FC<types.PageProps> = ({
const canonicalPageUrl =
!isDev && getCanonicalPageUrl(site, recordMap)(pageId)
const isBlogPost =
block.type === 'page' && block.parent_table === 'collection'
const socialImage = mapImageUrl(api.renderSocialImage(pageId))
const socialDescription =
getPageDescription(block, recordMap) ?? siteDescription
let comments: React.ReactNode = null
// only display comments on blog post pages
if (block.type === 'page' && block.parent_table === 'collection') {
if (isBlogPost) {
comments = (
<ReactUtterances
repo='transitive-bullshit/transitivebullsh.it'
@@ -112,6 +125,15 @@ export const NotionPage: React.FC<types.PageProps> = ({
<meta property='og:title' content={title} />
<meta property='og:site_name' content={site.name} />
{socialDescription && (
<>
<meta name='description' content={site.description} />
<meta property='og:site_name' content={site.name} />
</>
)}
{socialImage && <meta property='og:image' content={socialImage} />}
{canonicalPageUrl && <link rel='canonical' href={canonicalPageUrl} />}
<title>{title}</title>
@@ -158,9 +180,9 @@ export const NotionPage: React.FC<types.PageProps> = ({
darkMode={isDarkMode}
previewImages={site.previewImages !== false}
showCollectionViewDropdown={false}
defaultPageIcon='https://ssfy.io/https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F797768e4-f24a-4e65-bd4a-b622ae9671dc%252Fprofile-2020-280w-circle.png%3Ftable%3Dblock%26id%3D78fc5a4b-88d7-4b0e-824e-29407e9f1ec1%26cache%3Dv2'
defaultPageCover='https://ssfy.io/https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F9fc5ecae-2b4b-4e73-b0d4-918c829ba69f%252FIMG_0259-opt.jpg%3Ftable%3Dblock%26id%3D78fc5a4b-88d7-4b0e-824e-29407e9f1ec1%26cache%3Dv2'
defaultPageCoverPosition={0.1862}
defaultPageIcon={defaultPageIcon}
defaultPageCover={defaultPageCover}
defaultPageCoverPosition={defaultPageCoverPosition}
mapPageUrl={siteMapPageUrl}
mapImageUrl={mapNotionImageUrl}
searchNotion={searchNotion}

View File

@@ -1,34 +0,0 @@
pageLink: ({ href = '', ...rest }) => {
const parts = href
.split('?')[0]
.split('/')
.filter((p: string) => !!p.trim())
let pagesPath =
parts.length <= 1 ? '/[domain]' : '/[domain]/[pageId]'
let as = href
if (isDemo) {
pagesPath = '/[domain]'
} else if (isDev) {
// localhost
} else {
// prod, non-demo
as = `/${site.domain}${href}`
}
console.log({ href, parts, domain: site.domain, as })
// const MyButton = React.forwardRef(
// ({ href: href2, ...rest }, ref) => {
// return (
// <a {...rest} href={href2} ref={ref}>
// Click Me
// </a>
// )
// }
// )
return (
<Link href={pagesPath} as={as}>
<a href={as} {...rest} />
</Link>
)
}

View File

@@ -1,14 +1,45 @@
/**
* All app config that should be available client-side.
* Site-wide app configuration.
*
* @see env.ts for server-side version.
* @see env.ts for config relating to third-party dependencies.
*/
import { getEnv } from './get-env'
// this is the most important config value which specifies the site's root Notion page
export const rootNotionPageId = '78fc5a4b88d74b0e824e29407e9f1ec1'
// general site config
export const siteName = 'Transitive Bullshit'
export const siteFavicon = '/favicon.png'
export const siteAuthor = 'Travis Fischer'
export const siteDomain = 'transitivebullsh.it'
export const siteDescription =
'Personal site of Travis Fischer aka Transitive Bullshit'
// default notion values for site-wide consistency (may be overridden on a per-page basis)
export const defaultPageIcon =
'https://ssfy.io/https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F797768e4-f24a-4e65-bd4a-b622ae9671dc%252Fprofile-2020-280w-circle.png%3Ftable%3Dblock%26id%3D78fc5a4b-88d7-4b0e-824e-29407e9f1ec1%26cache%3Dv2'
export const defaultPageCover =
'https://ssfy.io/https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F9fc5ecae-2b4b-4e73-b0d4-918c829ba69f%252FIMG_0259-opt.jpg%3Ftable%3Dblock%26id%3D78fc5a4b-88d7-4b0e-824e-29407e9f1ec1%26cache%3Dv2'
export const defaultPageCoverPosition = 0.1862
// ----------------------------------------------------------------------------
export const isDev =
process.env.NODE_ENV === 'development' || !process.env.NODE_ENV
export const port = getEnv('PORT', '3000')
export const host = isDev ? `http://localhost:${port}` : `https://${siteDomain}`
export const apiBaseUrl = `${host}/api`
export const api = {
createPreviewImage: `${apiBaseUrl}/create-preview-image`,
searchNotion: `${apiBaseUrl}/search-notion`,
renderSocialImage: (pageId) => `${apiBaseUrl}/render-social-image/${pageId}`
}
export const fathomId = isDev ? null : getEnv('FATHOM_ID', null)
export const fathomConfig = fathomId
@@ -16,10 +47,3 @@ export const fathomConfig = fathomId
excludedDomains: ['localhost', 'localhost:3000']
}
: undefined
// TODO: fix duplication between server-side env and client-side config
export const apiBaseUrl = `/api`
export const api = {
createPreviewImage: `${apiBaseUrl}/create-preview-image`,
searchNotion: `${apiBaseUrl}/search-notion`
}

View File

@@ -1,23 +1,13 @@
/**
* All app config that needs to be available server-side.
* Config for third-party dependencies.
*
* @see config.ts for client-side version.
* - Google Cloud (Firebase) - used very simple database functionality.
* - Fathom - simple analytics.
*
* @see config.ts for primary configuration.
*/
import { getEnv } from './get-env'
import { isDev } from './config'
export * from './config'
export const port = getEnv('PORT', '3000')
export const domain = getEnv('DOMAIN')
export const host = isDev ? `http://localhost:${port}` : `https://${domain}`
export const apiBaseUrl = `${host}/api`
export const api = {
createPreviewImage: `${apiBaseUrl}/create-preview-image`,
searchNotion: `${apiBaseUrl}/search-notion`
}
export const googleProjectId = getEnv('GCLOUD_PROJECT')
@@ -40,14 +30,3 @@ try {
}
export const firebaseCollectionImages = getEnv('FIREBASE_COLLECTION_IMAGES')
export const notionRootPageId = getEnv('NOTION_ROOT_PAGE_ID')
export const siteName = getEnv('SITE_NAME', 'Transitive Bullshit')
export const siteDesc = getEnv(
'SITE_DESC',
'Personal site of Travis Fischer aka Transitive Bullshit.'
)
export const siteImage = getEnv('SITE_IMAGE', '/social.jpg')
export const siteFavicon = getEnv('SITE_FAVICON', '/favicon.png')
export const siteAuthor = getEnv('SITE_AUTHOR', 'Travis Fischer')

View File

@@ -0,0 +1,20 @@
import * as types from 'lib/types'
export function getPageDescription(
block: types.Block,
recordMap: types.RecordMap
): string | null {
const collection = recordMap.collection[block.parent_id]?.value
if (collection) {
const descriptionKey = Object.keys(collection.schema).find(
(key) => collection.schema[key].name === 'Description'
)
if (descriptionKey) {
return block.properties[descriptionKey]
}
}
return null
}

View File

@@ -1,7 +1,7 @@
import crypto from 'crypto'
import got from 'got'
import { api } from './env'
import { api } from './config'
import * as types from './types'
import * as db from './db'

View File

@@ -1,4 +1,4 @@
import * as config from './env'
import * as config from './config'
import * as types from './types'
export const getSiteForDomain = async (
@@ -7,8 +7,7 @@ export const getSiteForDomain = async (
return {
domain,
name: config.siteName,
rootNotionPageId: config.notionRootPageId,
description: config.siteDesc,
image: config.siteImage
rootNotionPageId: config.rootNotionPageId,
description: config.siteDescription
} as types.Site
}

View File

@@ -1,7 +1,7 @@
import { getSiteForDomain } from './get-site-for-domain'
import * as config from './env'
import * as config from './config'
import * as types from './types'
export async function getSites(): Promise<types.Site[]> {
return [await getSiteForDomain(config.domain)]
return [await getSiteForDomain(config.siteDomain)]
}

View File

@@ -26,6 +26,7 @@
},
"dependencies": {
"@google-cloud/firestore": "^4.8.1",
"chrome-aws-lambda": "^5.5.0",
"classnames": "^2.2.6",
"dangerously-set-html-content": "^1.0.8",
"fathom-client": "^3.0.0",
@@ -38,6 +39,8 @@
"notion-utils": "^3.1.1",
"p-map": "^4.0.0",
"p-memoize": "^4.0.0",
"puppeteer-core": "^5.5.0",
"puppeteer-social-image-transitive-bs": "^0.8.1",
"react": "17.0.1",
"react-body-classname": "^1.3.1",
"react-dom": "17.0.1",
@@ -63,6 +66,7 @@
"eslint-plugin-react": "^7.18.0",
"npm-run-all": "^4.1.5",
"prettier": "^2.0.5",
"puppeteer": "^5.5.0",
"typescript": "^4.0.2"
}
}

View File

@@ -1,5 +1,5 @@
import React from 'react'
import { isDev, domain } from 'lib/env'
import { isDev, siteDomain } from 'lib/config'
import { getSiteMaps } from 'lib/get-site-maps'
import { resolveNotionPage } from 'lib/resolve-notion-page'
import { NotionPage } from 'components'
@@ -8,11 +8,11 @@ export const getStaticProps = async (context) => {
const rawPageId = context.params.pageId as string
try {
const props = await resolveNotionPage(domain, rawPageId)
const props = await resolveNotionPage(siteDomain, rawPageId)
return { props, revalidate: 10 }
} catch (err) {
console.error('page error', domain, rawPageId, err)
console.error('page error', siteDomain, rawPageId, err)
return {
props: {

View File

@@ -1,13 +1,13 @@
import React from 'react'
import Document, { Html, Head, Main, NextScript } from 'next/document'
import * as config from 'lib/env'
import { siteFavicon } from 'lib/config'
export default class MyDocument extends Document {
render() {
return (
<Html lang='en'>
<Head>
<link rel='shortcut icon' href={config.siteFavicon} />
<link rel='shortcut icon' href={siteFavicon} />
<link
rel='apple-touch-icon'

View File

@@ -0,0 +1,115 @@
import { NextApiRequest, NextApiResponse } from 'next'
import chromium from 'chrome-aws-lambda'
import renderSocialImage from 'puppeteer-social-image-transitive-bs'
import { getBlockIcon, getBlockTitle } from 'notion-utils'
import { getPage } from 'lib/notion'
import * as types from 'lib/types'
import {
siteDescription,
defaultPageCover,
defaultPageIcon,
siteDomain,
siteName
} from 'lib/config'
import { getPageDescription } from 'lib/get-page-description'
export interface SocialImageConfig {
title: string
subtitle?: string
eyebrow?: string
logo?: string
imageUrl?: string
unsplashId?: string
unsplashKeywords?: string
backgroundImageAnchor?: string
backgroundImageOverlay?: boolean
background?: string
color?: string
googleFont?: string
fontFamily?: string
watermark?: string
size?:
| 'facebook'
| 'twitter'
| 'ig-landscape'
| 'ig-portrait'
| 'ig-square'
| 'ig-story'
}
export default async (req: NextApiRequest, res: NextApiResponse) => {
if (req.method !== 'GET') {
return res.status(405).send({ error: 'method not allowed' })
}
const pageId = req.query.pageId as string
if (!pageId) {
return res.status(400).send({ error: 'missing required parameter pageId' })
}
let recordMap: types.ExtendedRecordMap
let block: types.PageBlock
try {
recordMap = await getPage(pageId)
const pageBlockId = Object.keys(recordMap.block)[0]
block = recordMap.block[pageBlockId]?.value as types.PageBlock
if (!block) {
return res.status(404).send({
error: `unable to resolve root block for notion page "${pageId}"`
})
}
} catch (err) {
return res
.status(404)
.send({ error: `unable to load notion page "${pageId}"` })
}
// TODO: centralize these default config values
const image = await createSocialImage({
imageUrl: block.format?.page_cover ?? defaultPageCover,
title: getBlockTitle(block, recordMap) ?? siteName,
logo: getBlockIcon(block, recordMap) ?? defaultPageIcon,
subtitle: getPageDescription(block, recordMap) ?? siteDescription,
watermark: siteDomain
})
res.setHeader(
'Cache-Control',
'public, immutable, s-maxage=31536000, max-age=31536000, stale-while-revalidate=60'
)
res.setHeader('Content-Type', 'image/jpeg')
res.status(200).send(image)
}
async function createSocialImage(params: SocialImageConfig) {
let browser
try {
browser = await chromium.puppeteer.launch({
args: chromium.args,
defaultViewport: chromium.defaultViewport,
executablePath: await chromium.executablePath,
headless: true, // chromium.headless,
ignoreHTTPSErrors: true
})
const res = await renderSocialImage({
template: 'article',
templateParams: params,
templateStyles: `h1 { font-size: 96px; text-align: center; } h2 { font-size: 32px; }`,
size: params.size,
browser
})
return res
} finally {
if (browser) {
await browser.close()
}
}
}

View File

@@ -1,15 +1,15 @@
import React from 'react'
import { domain } from 'lib/env'
import { siteDomain } from 'lib/config'
import { resolveNotionPage } from 'lib/resolve-notion-page'
import { NotionPage } from 'components'
export const getStaticProps = async (context) => {
try {
const props = await resolveNotionPage(domain)
const props = await resolveNotionPage(siteDomain)
return { props, revalidate: 10 }
} catch (err) {
console.error('page error', domain, err)
console.error('page error', siteDomain, err)
return {
props: {

View File

@@ -5,8 +5,6 @@
"GOOGLE_APPLICATION_CREDENTIALS": "@transitive-bullshit-google-application-credentials",
"GCLOUD_PROJECT": "@transitive-bullshit-gcloud-project",
"FIREBASE_COLLECTION_IMAGES": "@transitive-bullshit-firebase-collection-images",
"DOMAIN": "@transitive-bullshit-domain",
"NOTION_ROOT_PAGE_ID": "@transitive-bullshit-notion-root-page-id",
"FATHOM_ID": "@transitive-bullshit-fathom-id"
}
}

208
yarn.lock
View File

@@ -111,6 +111,14 @@
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.11.tgz#9ce3595bcd74bc5c466905e86c535b8b25011e79"
integrity sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg==
"@babel/polyfill@^7.4.4":
version "7.12.1"
resolved "https://registry.yarnpkg.com/@babel/polyfill/-/polyfill-7.12.1.tgz#1f2d6371d1261bbd961f3c5d5909150e12d0bd96"
integrity sha512-X0pi0V6gxLi6lFZpGmeNa4zxtwEmCs42isWLNjZZDE0Y8yVfgu0T2OAHlzBbdYlqbW/YXVvoBHpATEM+goCj8g==
dependencies:
core-js "^2.6.5"
regenerator-runtime "^0.13.4"
"@babel/runtime@7.12.5", "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.1", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.2.0":
version "7.12.5"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e"
@@ -430,6 +438,13 @@
dependencies:
"@types/node" "*"
"@types/yauzl@^2.9.1":
version "2.9.1"
resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.9.1.tgz#d10f69f9f522eef3cf98e30afb684a1e1ec923af"
integrity sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA==
dependencies:
"@types/node" "*"
"@xobotyi/scrollbar-width@1.9.5":
version "1.9.5"
resolved "https://registry.yarnpkg.com/@xobotyi/scrollbar-width/-/scrollbar-width-1.9.5.tgz#80224a6919272f405b87913ca13b92929bdf3c4d"
@@ -470,6 +485,11 @@ adjust-sourcemap-loader@3.0.0:
loader-utils "^2.0.0"
regex-parser "^2.2.11"
agent-base@5:
version "5.1.1"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-5.1.1.tgz#e8fb3f242959db44d63be665db7a8e739537a32c"
integrity sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==
agent-base@6:
version "6.0.2"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
@@ -807,6 +827,11 @@ browserslist@4.14.6:
escalade "^3.1.1"
node-releases "^1.1.65"
buffer-crc32@~0.2.3:
version "0.2.13"
resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=
buffer-equal-constant-time@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819"
@@ -839,7 +864,7 @@ buffer@^4.3.0:
ieee754 "^1.1.4"
isarray "^1.0.0"
buffer@^5.5.0:
buffer@^5.2.1, buffer@^5.5.0:
version "5.7.1"
resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==
@@ -953,6 +978,13 @@ chownr@^2.0.0:
resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece"
integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==
chrome-aws-lambda@^5.5.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/chrome-aws-lambda/-/chrome-aws-lambda-5.5.0.tgz#5b011d1596020b6ab4b92b010e427da1be6fc628"
integrity sha512-nYSDzTsVEVsvIFaUUAUN53ulXBLKSRXFS+eVYZOLZD5SA1If59rqBAiy4raMgorQwXWqjSsjK1SF4As+qzPLqA==
dependencies:
lambdafs "^2.0.0"
cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de"
@@ -987,6 +1019,11 @@ clone-response@^1.0.2:
dependencies:
mimic-response "^1.0.0"
clone@2.x:
version "2.1.2"
resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=
code-point-at@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
@@ -1103,6 +1140,11 @@ copy-to-clipboard@^3.2.0:
dependencies:
toggle-selection "^1.0.6"
core-js@^2.6.5:
version "2.6.12"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec"
integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==
core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
@@ -1371,6 +1413,11 @@ detect-libc@^1.0.3:
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=
devtools-protocol@0.0.818844:
version "0.0.818844"
resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.818844.tgz#d1947278ec85b53e4c8ca598f607a28fa785ba9e"
integrity sha512-AD1hi7iVJ8OD0aMLQU5VK0XH9LDlA1+BcPIgrAxPfaibx2DbWucuyOhc4oyQCbnvDDO68nN6/LcKfqTP343Jjg==
diffie-hellman@^5.0.0:
version "5.0.3"
resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875"
@@ -1895,6 +1942,17 @@ extend@^3.0.2:
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
extract-zip@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a"
integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==
dependencies:
debug "^4.1.1"
get-stream "^5.1.0"
yauzl "^2.10.0"
optionalDependencies:
"@types/yauzl" "^2.9.1"
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
@@ -1935,6 +1993,13 @@ fathom-client@^3.0.0:
resolved "https://registry.yarnpkg.com/fathom-client/-/fathom-client-3.0.0.tgz#409c047cf1e2fea45b148e28d50fcd635e992893"
integrity sha512-d0oH2SHWCMIVLbbegB7nBIjSvbqbHrZBZxIOWSVAxlJL/roL0Ah9NNb6rTIcKMlA4gov9AjWQGEcZRzlnGc3XQ==
fd-slicer@~1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e"
integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=
dependencies:
pend "~1.2.0"
file-entry-cache@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.0.tgz#7921a89c391c6d93efec2169ac6bf300c527ea0a"
@@ -2198,6 +2263,25 @@ gzip-size@^6.0.0:
dependencies:
duplexer "^0.1.2"
handlebars-jest@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/handlebars-jest/-/handlebars-jest-0.5.0.tgz#a0df11060aafb70d643d2535ceb1e6e1ead21efd"
integrity sha512-lf4LzgGqdHE7hPL+XPb89z8m2uRkcSW8DKPQqYAub8KF9r76emGFtnARn7rvBpbGmxGome+4Uw46VpJYUFisNg==
dependencies:
node-cache "^4.2.0"
handlebars@^4.1.2:
version "4.7.6"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.6.tgz#d4c05c1baf90e9945f77aa68a7a219aa4a7df74e"
integrity sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==
dependencies:
minimist "^1.2.5"
neo-async "^2.6.0"
source-map "^0.6.1"
wordwrap "^1.0.0"
optionalDependencies:
uglify-js "^3.1.4"
has-flag@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
@@ -2315,6 +2399,14 @@ https-proxy-agent@5.0.0, https-proxy-agent@^5.0.0:
agent-base "6"
debug "4"
https-proxy-agent@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz#702b71fb5520a132a66de1f67541d9e62154d82b"
integrity sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==
dependencies:
agent-base "5"
debug "4"
hyphenate-style-name@^1.0.2:
version "1.0.4"
resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz#691879af8e220aea5750e8827db4ef62a54e361d"
@@ -2676,6 +2768,13 @@ keyv@^4.0.0:
dependencies:
json-buffer "3.0.1"
lambdafs@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/lambdafs/-/lambdafs-2.0.1.tgz#ddbee479e8e204dc17f1a43307ec3ae1df9ea485"
integrity sha512-RNb7Si2XPvU6pPiE6S0eDfH1W3n+OQaxpclSPJD0hnNFA5z+U1Ntr4sgUEE9xSxVu932ufh1iwtBcIxpEM9bOw==
dependencies:
tar-fs "^2.1.1"
levn@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
@@ -2769,7 +2868,7 @@ lodash.throttle@^4.1.1:
resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4"
integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=
lodash@^4.17.13, lodash@^4.17.19, lodash@^4.17.20:
lodash@^4.17.13, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20:
version "4.17.20"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
@@ -3006,6 +3105,11 @@ natural-compare@^1.4.0:
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
neo-async@^2.6.0:
version "2.6.2"
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
next-tick@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c"
@@ -3076,6 +3180,14 @@ node-addon-api@^3.0.0, node-addon-api@^3.0.2:
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.1.0.tgz#98b21931557466c6729e51cb77cd39c965f42239"
integrity sha512-flmrDNB06LIl5lywUz7YlNGZH/5p0M7W28k8hzd9Lshtdh1wshD2Y+U4h9LD6KObOy1f+fEVdgprPrEymjM5uw==
node-cache@^4.2.0:
version "4.2.1"
resolved "https://registry.yarnpkg.com/node-cache/-/node-cache-4.2.1.tgz#efd8474dee4edec4138cdded580f5516500f7334"
integrity sha512-BOb67bWg2dTyax5kdef5WfU3X8xu4wPg+zHzkvls0Q/QpYycIFRLEEIdAx9Wma43DxG6Qzn4illdZoYseKWa4A==
dependencies:
clone "2.x"
lodash "^4.17.15"
node-ensure@^0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/node-ensure/-/node-ensure-0.0.0.tgz#ecae764150de99861ec5c810fd5d096b183932a7"
@@ -3500,6 +3612,11 @@ pdfjs-dist@2.1.266:
node-ensure "^0.0.0"
worker-loader "^2.0.0"
pend@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA=
picomatch@^2.0.4, picomatch@^2.2.1:
version "2.2.2"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad"
@@ -3527,7 +3644,7 @@ pkg-dir@^2.0.0:
dependencies:
find-up "^2.1.0"
pkg-dir@^4.1.0:
pkg-dir@^4.1.0, pkg-dir@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==
@@ -3714,7 +3831,7 @@ process@0.11.10, process@^0.11.10:
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI=
progress@^2.0.0:
progress@^2.0.0, progress@^2.0.1:
version "2.0.3"
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
@@ -3747,6 +3864,11 @@ protobufjs@^6.10.2, protobufjs@^6.8.6:
"@types/node" "^13.7.0"
long "^4.0.0"
proxy-from-env@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
public-encrypt@^4.0.0:
version "4.0.3"
resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0"
@@ -3782,6 +3904,51 @@ punycode@^2.1.0:
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
puppeteer-core@^5.5.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/puppeteer-core/-/puppeteer-core-5.5.0.tgz#dfb6266efe5a933cbf1a368d27025a6fd4f5a884"
integrity sha512-tlA+1n+ziW/Db03hVV+bAecDKse8ihFRXYiEypBe9IlLRvOCzYFG6qrCMBYK34HO/Q/Ecjc+tvkHRAfLVH+NgQ==
dependencies:
debug "^4.1.0"
devtools-protocol "0.0.818844"
extract-zip "^2.0.0"
https-proxy-agent "^4.0.0"
node-fetch "^2.6.1"
pkg-dir "^4.2.0"
progress "^2.0.1"
proxy-from-env "^1.0.0"
rimraf "^3.0.2"
tar-fs "^2.0.0"
unbzip2-stream "^1.3.3"
ws "^7.2.3"
puppeteer-social-image-transitive-bs@^0.8.1:
version "0.8.1"
resolved "https://registry.yarnpkg.com/puppeteer-social-image-transitive-bs/-/puppeteer-social-image-transitive-bs-0.8.1.tgz#388379fd555e9ce4798629099dd4e6c0bcf161be"
integrity sha512-jYasq40M/p8gmeBYGj5/vVTwRnY2eHG9HhMBLazVPl6x4Pu7pFF9MTVkB+NLHJvyIsaayeLht+TYrnIEGXBCHg==
dependencies:
"@babel/polyfill" "^7.4.4"
handlebars "^4.1.2"
handlebars-jest "^0.5.0"
puppeteer@^5.5.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-5.5.0.tgz#331a7edd212ca06b4a556156435f58cbae08af00"
integrity sha512-OM8ZvTXAhfgFA7wBIIGlPQzvyEETzDjeRa4mZRCRHxYL+GNH5WAuYUQdja3rpWZvkX/JKqmuVgbsxDNsDFjMEg==
dependencies:
debug "^4.1.0"
devtools-protocol "0.0.818844"
extract-zip "^2.0.0"
https-proxy-agent "^4.0.0"
node-fetch "^2.6.1"
pkg-dir "^4.2.0"
progress "^2.0.1"
proxy-from-env "^1.0.0"
rimraf "^3.0.2"
tar-fs "^2.0.0"
unbzip2-stream "^1.3.3"
ws "^7.2.3"
querystring-es3@^0.2.0:
version "0.2.1"
resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
@@ -4839,6 +5006,11 @@ throttle-debounce@^2.1.0:
resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-2.3.0.tgz#fd31865e66502071e411817e241465b3e9c372e2"
integrity sha512-H7oLPV0P7+jgvrk+6mwwwBDmxTaxnu9HMXmloNLXwnNO0ZxZ31Orah2n8lU1eMPvsaowP2CX+USCgyovXfdOFQ==
through@^2.3.8:
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
timers-browserify@^2.0.4:
version "2.0.12"
resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.12.tgz#44a45c11fbf407f34f97bccd1577c652361b00ee"
@@ -4959,6 +5131,19 @@ typescript@^4.0.2:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.3.tgz#519d582bd94cba0cf8934c7d8e8467e473f53bb7"
integrity sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==
uglify-js@^3.1.4:
version "3.12.4"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.12.4.tgz#93de48bb76bb3ec0fc36563f871ba46e2ee5c7ee"
integrity sha512-L5i5jg/SHkEqzN18gQMTWsZk3KelRsfD1wUVNqtq0kzqWQqcJjyL8yc1o8hJgRrWqrAl2mUFbhfznEIoi7zi2A==
unbzip2-stream@^1.3.3:
version "1.4.3"
resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7"
integrity sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==
dependencies:
buffer "^5.2.1"
through "^2.3.8"
unfetch@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-4.2.0.tgz#7e21b0ef7d363d8d9af0fb929a5555f6ef97a3be"
@@ -5118,6 +5303,11 @@ word-wrap@^1.2.3:
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==
wordwrap@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=
worker-loader@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/worker-loader/-/worker-loader-2.0.0.tgz#45fda3ef76aca815771a89107399ee4119b430ac"
@@ -5131,7 +5321,7 @@ wrappy@1:
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
ws@^7.3.1:
ws@^7.2.3, ws@^7.3.1:
version "7.4.2"
resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.2.tgz#782100048e54eb36fe9843363ab1c68672b261dd"
integrity sha512-T4tewALS3+qsrpGI/8dqNMLIVdq/g/85U98HPMa6F0m6xTbvhXU6RCQLqPH3+SlomNV/LdY6RXEbBpMH6EOJnA==
@@ -5146,6 +5336,14 @@ yallist@^4.0.0:
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
yauzl@^2.10.0:
version "2.10.0"
resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9"
integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=
dependencies:
buffer-crc32 "~0.2.3"
fd-slicer "~1.1.0"
yocto-queue@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"