mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-24 11:49:13 +00:00
Compare commits
18 Commits
@vercel/fr
...
@vercel/fr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb29bfdd68 | ||
|
|
5ba2d61c77 | ||
|
|
879096fff3 | ||
|
|
99e40272cf | ||
|
|
04e9f771df | ||
|
|
6f21f1081d | ||
|
|
d806c9f846 | ||
|
|
71cc4ca865 | ||
|
|
21f25f5eb0 | ||
|
|
2a492fa7ec | ||
|
|
f8ca24b226 | ||
|
|
019590e845 | ||
|
|
6180701f8d | ||
|
|
b1c7ca8e91 | ||
|
|
dbc00a7c3e | ||
|
|
5ae7c2f452 | ||
|
|
0cbc676a6f | ||
|
|
61e588cd63 |
3
.github/CODEOWNERS
vendored
3
.github/CODEOWNERS
vendored
@@ -7,11 +7,10 @@
|
||||
/packages/cli/src/commands/certs @mglagola @anatrajkovska
|
||||
/packages/cli/src/commands/env @TooTallNate @EndangeredMassa @styfle @cb1kenobi @Ethan-Arrowood
|
||||
/packages/fs-detectors @TooTallNate @EndangeredMassa @styfle @cb1kenobi @Ethan-Arrowood @agadzik @chloetedder
|
||||
/packages/middleware @gdborton @vercel/edge-function
|
||||
/packages/node-bridge @TooTallNate @EndangeredMassa @styfle @cb1kenobi @Ethan-Arrowood @ijjk
|
||||
/packages/next @TooTallNate @EndangeredMassa @styfle @cb1kenobi @Ethan-Arrowood @ijjk
|
||||
/packages/routing-utils @TooTallNate @EndangeredMassa @styfle @cb1kenobi @Ethan-Arrowood @ijjk
|
||||
/packages/edge @vercel/edge-function
|
||||
/packages/edge @vercel/edge-compute
|
||||
/examples @leerob
|
||||
/examples/create-react-app @Timer
|
||||
/examples/nextjs @timneutkens @ijjk @styfle
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -28,4 +28,5 @@ test/lib/deployment/failed-page.txt
|
||||
__pycache__
|
||||
.vercel
|
||||
.turbo
|
||||
.eslintcache
|
||||
turbo-cache-key.json
|
||||
|
||||
4
examples/nextjs/.gitignore
vendored
4
examples/nextjs/.gitignore
vendored
@@ -30,7 +30,3 @@ yarn-error.log*
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
|
||||
@@ -18,6 +18,8 @@ You can start editing the page by modifying `pages/index.js`. The page auto-upda
|
||||
|
||||
The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
|
||||
|
||||
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
|
||||
|
||||
## Learn More
|
||||
|
||||
To learn more about Next.js, take a look at the following resources:
|
||||
|
||||
618
examples/nextjs/package-lock.json
generated
618
examples/nextjs/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -9,9 +9,10 @@
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"eslint": "8.28.0",
|
||||
"eslint-config-next": "13.0.6",
|
||||
"next": "13.0.6",
|
||||
"@next/font": "13.1.0",
|
||||
"eslint": "8.30.0",
|
||||
"eslint-config-next": "13.1.0",
|
||||
"next": "13.1.0",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import '../styles/globals.css'
|
||||
|
||||
function MyApp({ Component, pageProps }) {
|
||||
export default function App({ Component, pageProps }) {
|
||||
return <Component {...pageProps} />
|
||||
}
|
||||
|
||||
export default MyApp
|
||||
|
||||
13
examples/nextjs/pages/_document.js
Normal file
13
examples/nextjs/pages/_document.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import { Html, Head, Main, NextScript } from 'next/document'
|
||||
|
||||
export default function Document() {
|
||||
return (
|
||||
<Html lang="en">
|
||||
<Head />
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
)
|
||||
}
|
||||
@@ -1,71 +1,123 @@
|
||||
import Head from 'next/head'
|
||||
import Image from 'next/image'
|
||||
import { Inter } from '@next/font/google'
|
||||
import styles from '../styles/Home.module.css'
|
||||
|
||||
const inter = Inter({ subsets: ['latin'] })
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<>
|
||||
<Head>
|
||||
<title>Create Next App</title>
|
||||
<meta name="description" content="Generated by create next app" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
</Head>
|
||||
|
||||
<main className={styles.main}>
|
||||
<h1 className={styles.title}>
|
||||
Welcome to <a href="https://nextjs.org">Next.js!</a>
|
||||
</h1>
|
||||
<div className={styles.description}>
|
||||
<p>
|
||||
Get started by editing
|
||||
<code className={styles.code}>pages/index.js</code>
|
||||
</p>
|
||||
<div>
|
||||
<a
|
||||
href="https://vercel.com?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
By{' '}
|
||||
<Image
|
||||
src="/vercel.svg"
|
||||
alt="Vercel Logo"
|
||||
className={styles.vercelLogo}
|
||||
width={100}
|
||||
height={24}
|
||||
priority
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p className={styles.description}>
|
||||
Get started by editing{' '}
|
||||
<code className={styles.code}>pages/index.js</code>
|
||||
</p>
|
||||
<div className={styles.center}>
|
||||
<Image
|
||||
className={styles.logo}
|
||||
src="/next.svg"
|
||||
alt="Next.js Logo"
|
||||
width={180}
|
||||
height={37}
|
||||
priority
|
||||
/>
|
||||
<div className={styles.thirteen}>
|
||||
<Image
|
||||
src="/thirteen.svg"
|
||||
alt="13"
|
||||
width={40}
|
||||
height={31}
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.grid}>
|
||||
<a href="https://nextjs.org/docs" className={styles.card}>
|
||||
<h2>Documentation →</h2>
|
||||
<p>Find in-depth information about Next.js features and API.</p>
|
||||
</a>
|
||||
|
||||
<a href="https://nextjs.org/learn" className={styles.card}>
|
||||
<h2>Learn →</h2>
|
||||
<p>Learn about Next.js in an interactive course with quizzes!</p>
|
||||
<a
|
||||
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
|
||||
className={styles.card}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<h2 className={inter.className}>
|
||||
Docs <span>-></span>
|
||||
</h2>
|
||||
<p className={inter.className}>
|
||||
Find in-depth information about Next.js features and API.
|
||||
</p>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="https://github.com/vercel/next.js/tree/canary/examples"
|
||||
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
|
||||
className={styles.card}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<h2>Examples →</h2>
|
||||
<p>Discover and deploy boilerplate example Next.js projects.</p>
|
||||
<h2 className={inter.className}>
|
||||
Learn <span>-></span>
|
||||
</h2>
|
||||
<p className={inter.className}>
|
||||
Learn about Next.js in an interactive course with quizzes!
|
||||
</p>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
|
||||
className={styles.card}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<h2 className={inter.className}>
|
||||
Templates <span>-></span>
|
||||
</h2>
|
||||
<p className={inter.className}>
|
||||
Discover and deploy boilerplate example Next.js projects.
|
||||
</p>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
|
||||
className={styles.card}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className={styles.card}
|
||||
>
|
||||
<h2>Deploy →</h2>
|
||||
<p>
|
||||
Instantly deploy your Next.js site to a public URL with Vercel.
|
||||
<h2 className={inter.className}>
|
||||
Deploy <span>-></span>
|
||||
</h2>
|
||||
<p className={inter.className}>
|
||||
Instantly deploy your Next.js site to a shareable URL
|
||||
with Vercel.
|
||||
</p>
|
||||
</a>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer className={styles.footer}>
|
||||
<a
|
||||
href="https://vercel.com?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Powered by{' '}
|
||||
<span className={styles.logo}>
|
||||
<Image src="/vercel.svg" alt="Vercel Logo" width={72} height={16} />
|
||||
</span>
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
1
examples/nextjs/public/next.svg
Normal file
1
examples/nextjs/public/next.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
1
examples/nextjs/public/thirteen.svg
Normal file
1
examples/nextjs/public/thirteen.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="31" fill="none"><g opacity=".9"><path fill="url(#a)" d="M13 .4v29.3H7V6.3h-.2L0 10.5V5L7.2.4H13Z"/><path fill="url(#b)" d="M28.8 30.1c-2.2 0-4-.3-5.7-1-1.7-.8-3-1.8-4-3.1a7.7 7.7 0 0 1-1.4-4.6h6.2c0 .8.3 1.4.7 2 .4.5 1 .9 1.7 1.2.7.3 1.6.4 2.5.4 1 0 1.7-.2 2.5-.5.7-.3 1.3-.8 1.7-1.4.4-.6.6-1.2.6-2s-.2-1.5-.7-2.1c-.4-.6-1-1-1.8-1.4-.8-.4-1.8-.5-2.9-.5h-2.7v-4.6h2.7a6 6 0 0 0 2.5-.5 4 4 0 0 0 1.7-1.3c.4-.6.6-1.3.6-2a3.5 3.5 0 0 0-2-3.3 5.6 5.6 0 0 0-4.5 0 4 4 0 0 0-1.7 1.2c-.4.6-.6 1.2-.6 2h-6c0-1.7.6-3.2 1.5-4.5 1-1.3 2.2-2.3 3.8-3C25 .4 26.8 0 28.8 0s3.8.4 5.3 1.1c1.5.7 2.7 1.7 3.6 3a7.2 7.2 0 0 1 1.2 4.2c0 1.6-.5 3-1.5 4a7 7 0 0 1-4 2.2v.2c2.2.3 3.8 1 5 2.2a6.4 6.4 0 0 1 1.6 4.6c0 1.7-.5 3.1-1.4 4.4a9.7 9.7 0 0 1-4 3.1c-1.7.8-3.7 1.1-5.8 1.1Z"/></g><defs><linearGradient id="a" x1="20" x2="20" y1="0" y2="30.1" gradientUnits="userSpaceOnUse"><stop/><stop offset="1" stop-color="#3D3D3D"/></linearGradient><linearGradient id="b" x1="20" x2="20" y1="0" y2="30.1" gradientUnits="userSpaceOnUse"><stop/><stop offset="1" stop-color="#3D3D3D"/></linearGradient></defs></svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -1,4 +1 @@
|
||||
<svg width="283" height="64" viewBox="0 0 283 64" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M141.04 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.46 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM248.72 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.45 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM200.24 34c0 6 3.92 10 10 10 4.12 0 7.21-1.87 8.8-4.92l7.68 4.43c-3.18 5.3-9.14 8.49-16.48 8.49-11.05 0-19-7.2-19-18s7.96-18 19-18c7.34 0 13.29 3.19 16.48 8.49l-7.68 4.43c-1.59-3.05-4.68-4.92-8.8-4.92-6.07 0-10 4-10 10zm82.48-29v46h-9V5h9zM36.95 0L73.9 64H0L36.95 0zm92.38 5l-27.71 48L73.91 5H84.3l17.32 30 17.32-30h10.39zm58.91 12v9.69c-1-.29-2.06-.49-3.2-.49-5.81 0-10 4-10 10V51h-9V17h9v9.2c0-5.08 5.91-9.2 13.2-9.2z" fill="#000"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 283 64"><path fill="black" d="M141 16c-11 0-19 7-19 18s9 18 20 18c7 0 13-3 16-7l-7-5c-2 3-6 4-9 4-5 0-9-3-10-7h28v-3c0-11-8-18-19-18zm-9 15c1-4 4-7 9-7s8 3 9 7h-18zm117-15c-11 0-19 7-19 18s9 18 20 18c6 0 12-3 16-7l-8-5c-2 3-5 4-8 4-5 0-9-3-11-7h28l1-3c0-11-8-18-19-18zm-10 15c2-4 5-7 10-7s8 3 9 7h-19zm-39 3c0 6 4 10 10 10 4 0 7-2 9-5l8 5c-3 5-9 8-17 8-11 0-19-7-19-18s8-18 19-18c8 0 14 3 17 8l-8 5c-2-3-5-5-9-5-6 0-10 4-10 10zm83-29v46h-9V5h9zM37 0l37 64H0L37 0zm92 5-27 48L74 5h10l18 30 17-30h10zm59 12v10l-3-1c-6 0-10 4-10 10v15h-9V17h9v9c0-5 6-9 13-9z"/></svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 629 B |
@@ -1,129 +1,278 @@
|
||||
.container {
|
||||
padding: 0 2rem;
|
||||
}
|
||||
|
||||
.main {
|
||||
min-height: 100vh;
|
||||
padding: 4rem 0;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 6rem;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
padding: 2rem 0;
|
||||
border-top: 1px solid #eaeaea;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
.description {
|
||||
display: inherit;
|
||||
justify-content: inherit;
|
||||
align-items: inherit;
|
||||
font-size: 0.85rem;
|
||||
max-width: var(--max-width);
|
||||
width: 100%;
|
||||
z-index: 2;
|
||||
font-family: var(--font-mono);
|
||||
}
|
||||
|
||||
.footer a {
|
||||
.description a {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-grow: 1;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.title a {
|
||||
color: #0070f3;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.title a:hover,
|
||||
.title a:focus,
|
||||
.title a:active {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.title {
|
||||
.description p {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
line-height: 1.15;
|
||||
font-size: 4rem;
|
||||
}
|
||||
|
||||
.title,
|
||||
.description {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.description {
|
||||
margin: 4rem 0;
|
||||
line-height: 1.5;
|
||||
font-size: 1.5rem;
|
||||
padding: 1rem;
|
||||
background-color: rgba(var(--callout-rgb), 0.5);
|
||||
border: 1px solid rgba(var(--callout-border-rgb), 0.3);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
.code {
|
||||
background: #fafafa;
|
||||
border-radius: 5px;
|
||||
padding: 0.75rem;
|
||||
font-size: 1.1rem;
|
||||
font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
|
||||
Bitstream Vera Sans Mono, Courier New, monospace;
|
||||
font-weight: 700;
|
||||
font-family: var(--font-mono);
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
max-width: 800px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(25%, auto));
|
||||
width: var(--max-width);
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.card {
|
||||
margin: 1rem;
|
||||
padding: 1.5rem;
|
||||
text-align: left;
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
border: 1px solid #eaeaea;
|
||||
border-radius: 10px;
|
||||
transition: color 0.15s ease, border-color 0.15s ease;
|
||||
max-width: 300px;
|
||||
padding: 1rem 1.2rem;
|
||||
border-radius: var(--border-radius);
|
||||
background: rgba(var(--card-rgb), 0);
|
||||
border: 1px solid rgba(var(--card-border-rgb), 0);
|
||||
transition: background 200ms, border 200ms;
|
||||
}
|
||||
|
||||
.card:hover,
|
||||
.card:focus,
|
||||
.card:active {
|
||||
color: #0070f3;
|
||||
border-color: #0070f3;
|
||||
.card span {
|
||||
display: inline-block;
|
||||
transition: transform 200ms;
|
||||
}
|
||||
|
||||
.card h2 {
|
||||
margin: 0 0 1rem 0;
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.7rem;
|
||||
}
|
||||
|
||||
.card p {
|
||||
margin: 0;
|
||||
font-size: 1.25rem;
|
||||
opacity: 0.6;
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.5;
|
||||
max-width: 30ch;
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: 1em;
|
||||
margin-left: 0.5rem;
|
||||
.center {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
padding: 4rem 0;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.center::before {
|
||||
background: var(--secondary-glow);
|
||||
border-radius: 50%;
|
||||
width: 480px;
|
||||
height: 360px;
|
||||
margin-left: -400px;
|
||||
}
|
||||
|
||||
.center::after {
|
||||
background: var(--primary-glow);
|
||||
width: 240px;
|
||||
height: 180px;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.center::before,
|
||||
.center::after {
|
||||
content: '';
|
||||
left: 50%;
|
||||
position: absolute;
|
||||
filter: blur(45px);
|
||||
transform: translateZ(0);
|
||||
}
|
||||
|
||||
.logo,
|
||||
.thirteen {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.thirteen {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 75px;
|
||||
height: 75px;
|
||||
padding: 25px 10px;
|
||||
margin-left: 16px;
|
||||
transform: translateZ(0);
|
||||
border-radius: var(--border-radius);
|
||||
overflow: hidden;
|
||||
box-shadow: 0px 2px 8px -1px #0000001a;
|
||||
}
|
||||
|
||||
.thirteen::before,
|
||||
.thirteen::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
/* Conic Gradient Animation */
|
||||
.thirteen::before {
|
||||
animation: 6s rotate linear infinite;
|
||||
width: 200%;
|
||||
height: 200%;
|
||||
background: var(--tile-border);
|
||||
}
|
||||
|
||||
/* Inner Square */
|
||||
.thirteen::after {
|
||||
inset: 0;
|
||||
padding: 1px;
|
||||
border-radius: var(--border-radius);
|
||||
background: linear-gradient(
|
||||
to bottom right,
|
||||
rgba(var(--tile-start-rgb), 1),
|
||||
rgba(var(--tile-end-rgb), 1)
|
||||
);
|
||||
background-clip: content-box;
|
||||
}
|
||||
|
||||
/* Enable hover only on non-touch devices */
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
.card:hover {
|
||||
background: rgba(var(--card-rgb), 0.1);
|
||||
border: 1px solid rgba(var(--card-border-rgb), 0.15);
|
||||
}
|
||||
|
||||
.card:hover span {
|
||||
transform: translateX(4px);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion) {
|
||||
.thirteen::before {
|
||||
animation: none;
|
||||
}
|
||||
|
||||
.card:hover span {
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mobile */
|
||||
@media (max-width: 700px) {
|
||||
.content {
|
||||
padding: 4rem;
|
||||
}
|
||||
|
||||
.grid {
|
||||
grid-template-columns: 1fr;
|
||||
margin-bottom: 120px;
|
||||
max-width: 320px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 1rem 2.5rem;
|
||||
}
|
||||
|
||||
.card h2 {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.center {
|
||||
padding: 8rem 0 6rem;
|
||||
}
|
||||
|
||||
.center::before {
|
||||
transform: none;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.description a {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.description p,
|
||||
.description div {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.description p {
|
||||
align-items: center;
|
||||
inset: 0 0 auto;
|
||||
padding: 2rem 1rem 1.4rem;
|
||||
border-radius: 0;
|
||||
border: none;
|
||||
border-bottom: 1px solid rgba(var(--callout-border-rgb), 0.25);
|
||||
background: linear-gradient(
|
||||
to bottom,
|
||||
rgba(var(--background-start-rgb), 1),
|
||||
rgba(var(--callout-rgb), 0.5)
|
||||
);
|
||||
background-clip: padding-box;
|
||||
backdrop-filter: blur(24px);
|
||||
}
|
||||
|
||||
.description div {
|
||||
align-items: flex-end;
|
||||
pointer-events: none;
|
||||
inset: auto 0 0;
|
||||
padding: 2rem;
|
||||
height: 200px;
|
||||
background: linear-gradient(
|
||||
to bottom,
|
||||
transparent 0%,
|
||||
rgb(var(--background-end-rgb)) 40%
|
||||
);
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Tablet and Smaller Desktop */
|
||||
@media (min-width: 701px) and (max-width: 1120px) {
|
||||
.grid {
|
||||
grid-template-columns: repeat(2, 50%);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.card,
|
||||
.footer {
|
||||
border-color: #222;
|
||||
}
|
||||
.code {
|
||||
background: #111;
|
||||
}
|
||||
.logo img {
|
||||
.vercelLogo {
|
||||
filter: invert(1);
|
||||
}
|
||||
|
||||
.logo,
|
||||
.thirteen img {
|
||||
filter: invert(1) drop-shadow(0 0 0.3rem #ffffff70);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rotate {
|
||||
from {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,98 @@
|
||||
html,
|
||||
body {
|
||||
:root {
|
||||
--max-width: 1100px;
|
||||
--border-radius: 12px;
|
||||
--font-mono: ui-monospace, Menlo, Monaco, 'Cascadia Mono', 'Segoe UI Mono',
|
||||
'Roboto Mono', 'Oxygen Mono', 'Ubuntu Monospace', 'Source Code Pro',
|
||||
'Fira Mono', 'Droid Sans Mono', 'Courier New', monospace;
|
||||
|
||||
--foreground-rgb: 0, 0, 0;
|
||||
--background-start-rgb: 214, 219, 220;
|
||||
--background-end-rgb: 255, 255, 255;
|
||||
|
||||
--primary-glow: conic-gradient(
|
||||
from 180deg at 50% 50%,
|
||||
#16abff33 0deg,
|
||||
#0885ff33 55deg,
|
||||
#54d6ff33 120deg,
|
||||
#0071ff33 160deg,
|
||||
transparent 360deg
|
||||
);
|
||||
--secondary-glow: radial-gradient(
|
||||
rgba(255, 255, 255, 1),
|
||||
rgba(255, 255, 255, 0)
|
||||
);
|
||||
|
||||
--tile-start-rgb: 239, 245, 249;
|
||||
--tile-end-rgb: 228, 232, 233;
|
||||
--tile-border: conic-gradient(
|
||||
#00000080,
|
||||
#00000040,
|
||||
#00000030,
|
||||
#00000020,
|
||||
#00000010,
|
||||
#00000010,
|
||||
#00000080
|
||||
);
|
||||
|
||||
--callout-rgb: 238, 240, 241;
|
||||
--callout-border-rgb: 172, 175, 176;
|
||||
--card-rgb: 180, 185, 188;
|
||||
--card-border-rgb: 131, 134, 135;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--foreground-rgb: 255, 255, 255;
|
||||
--background-start-rgb: 0, 0, 0;
|
||||
--background-end-rgb: 0, 0, 0;
|
||||
|
||||
--primary-glow: radial-gradient(rgba(1, 65, 255, 0.4), rgba(1, 65, 255, 0));
|
||||
--secondary-glow: linear-gradient(
|
||||
to bottom right,
|
||||
rgba(1, 65, 255, 0),
|
||||
rgba(1, 65, 255, 0),
|
||||
rgba(1, 65, 255, 0.3)
|
||||
);
|
||||
|
||||
--tile-start-rgb: 2, 13, 46;
|
||||
--tile-end-rgb: 2, 5, 19;
|
||||
--tile-border: conic-gradient(
|
||||
#ffffff80,
|
||||
#ffffff40,
|
||||
#ffffff30,
|
||||
#ffffff20,
|
||||
#ffffff10,
|
||||
#ffffff10,
|
||||
#ffffff80
|
||||
);
|
||||
|
||||
--callout-rgb: 20, 20, 20;
|
||||
--callout-border-rgb: 108, 108, 108;
|
||||
--card-rgb: 100, 100, 100;
|
||||
--card-border-rgb: 200, 200, 200;
|
||||
}
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
|
||||
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
max-width: 100vw;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
body {
|
||||
color: rgb(var(--foreground-rgb));
|
||||
background: linear-gradient(
|
||||
to bottom,
|
||||
transparent,
|
||||
rgb(var(--background-end-rgb))
|
||||
)
|
||||
rgb(var(--background-start-rgb));
|
||||
}
|
||||
|
||||
a {
|
||||
@@ -11,16 +100,8 @@ a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
html {
|
||||
color-scheme: dark;
|
||||
}
|
||||
body {
|
||||
color: white;
|
||||
background: black;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
"test-integration-cli": "node utils/gen.js && turbo run test-integration-cli",
|
||||
"test-integration-once": "node utils/gen.js && turbo run test-integration-once",
|
||||
"test-integration-dev": "node utils/gen.js && turbo run test-integration-dev",
|
||||
"lint": "eslint . --ext .ts,.js",
|
||||
"lint": "eslint . --cache --ext .ts,.js",
|
||||
"prepare": "husky install",
|
||||
"pack": "cd utils && node -r ts-eager/register ./pack.ts"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/build-utils",
|
||||
"version": "5.7.1",
|
||||
"version": "5.7.2",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.js",
|
||||
|
||||
@@ -2,18 +2,23 @@ import path from 'path';
|
||||
import debug from '../debug';
|
||||
import FileFsRef from '../file-fs-ref';
|
||||
import { File, Files, Meta } from '../types';
|
||||
import { remove, mkdirp, readlink, symlink } from 'fs-extra';
|
||||
import { remove, mkdirp, readlink, symlink, Stats } from 'fs-extra';
|
||||
import streamToBuffer from './stream-to-buffer';
|
||||
|
||||
export interface DownloadedFiles {
|
||||
[filePath: string]: FileFsRef;
|
||||
}
|
||||
|
||||
const S_IFMT = 61440; /* 0170000 type of file */
|
||||
const S_IFLNK = 40960; /* 0120000 symbolic link */
|
||||
const STAT = new Stats();
|
||||
|
||||
export function isSymbolicLink(mode: number): boolean {
|
||||
return (mode & S_IFMT) === S_IFLNK;
|
||||
STAT.mode = mode;
|
||||
return STAT.isSymbolicLink();
|
||||
}
|
||||
|
||||
export function isDirectory(mode: number): boolean {
|
||||
STAT.mode = mode;
|
||||
return STAT.isDirectory();
|
||||
}
|
||||
|
||||
async function prepareSymlinkTarget(
|
||||
@@ -46,6 +51,11 @@ export async function downloadFile(
|
||||
): Promise<FileFsRef> {
|
||||
const { mode } = file;
|
||||
|
||||
if (isDirectory(mode)) {
|
||||
await mkdirp(fsPath);
|
||||
return FileFsRef.fromFsPath({ mode, fsPath });
|
||||
}
|
||||
|
||||
// If the source is a symlink, try to create it instead of copying the file.
|
||||
// Note: creating symlinks on Windows requires admin priviliges or symlinks
|
||||
// enabled in the group policy. We may want to improve the error message.
|
||||
|
||||
@@ -15,12 +15,7 @@ export default async function glob(
|
||||
opts: GlobOptions | string,
|
||||
mountpoint?: string
|
||||
): Promise<Record<string, FileFsRef>> {
|
||||
let options: GlobOptions;
|
||||
if (typeof opts === 'string') {
|
||||
options = { cwd: opts };
|
||||
} else {
|
||||
options = opts;
|
||||
}
|
||||
const options: GlobOptions = typeof opts === 'string' ? { cwd: opts } : opts;
|
||||
|
||||
if (!options.cwd) {
|
||||
throw new Error(
|
||||
@@ -34,13 +29,18 @@ export default async function glob(
|
||||
|
||||
const results: Record<string, FileFsRef> = {};
|
||||
const statCache: Record<string, Stats> = {};
|
||||
const symlinks: Record<string, boolean | undefined> = {};
|
||||
|
||||
options.symlinks = {};
|
||||
options.statCache = statCache;
|
||||
options.stat = true;
|
||||
options.dot = true;
|
||||
const files = await vanillaGlob(pattern, {
|
||||
...options,
|
||||
symlinks,
|
||||
statCache,
|
||||
stat: true,
|
||||
dot: true,
|
||||
});
|
||||
|
||||
const files = await vanillaGlob(pattern, options);
|
||||
const dirs = new Set<string>();
|
||||
const dirsWithEntries = new Set<string>();
|
||||
|
||||
for (const relativePath of files) {
|
||||
const fsPath = normalizePath(path.join(options.cwd, relativePath));
|
||||
@@ -49,12 +49,20 @@ export default async function glob(
|
||||
stat,
|
||||
`statCache does not contain value for ${relativePath} (resolved to ${fsPath})`
|
||||
);
|
||||
const isSymlink = options.symlinks![fsPath];
|
||||
if (isSymlink || stat.isFile()) {
|
||||
const isSymlink = symlinks[fsPath];
|
||||
if (isSymlink || stat.isFile() || stat.isDirectory()) {
|
||||
if (isSymlink) {
|
||||
stat = await lstat(fsPath);
|
||||
}
|
||||
|
||||
// Some bookkeeping to track which directories already have entries within
|
||||
const dirname = path.dirname(relativePath);
|
||||
dirsWithEntries.add(dirname);
|
||||
if (stat.isDirectory()) {
|
||||
dirs.add(relativePath);
|
||||
continue;
|
||||
}
|
||||
|
||||
let finalPath = relativePath;
|
||||
if (mountpoint) {
|
||||
finalPath = path.join(mountpoint, finalPath);
|
||||
@@ -64,5 +72,20 @@ export default async function glob(
|
||||
}
|
||||
}
|
||||
|
||||
// Add empty directory entries
|
||||
for (const relativePath of dirs) {
|
||||
if (dirsWithEntries.has(relativePath)) continue;
|
||||
|
||||
let finalPath = relativePath;
|
||||
if (mountpoint) {
|
||||
finalPath = path.join(mountpoint, finalPath);
|
||||
}
|
||||
|
||||
const fsPath = normalizePath(path.join(options.cwd, relativePath));
|
||||
const stat = statCache[fsPath];
|
||||
|
||||
results[finalPath] = new FileFsRef({ mode: stat.mode, fsPath });
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
195
packages/build-utils/test/unit.download.test.ts
vendored
Normal file
195
packages/build-utils/test/unit.download.test.ts
vendored
Normal file
@@ -0,0 +1,195 @@
|
||||
import path from 'path';
|
||||
import fs, { readlink } from 'fs-extra';
|
||||
import { strict as assert, strictEqual } from 'assert';
|
||||
import { download, glob, FileBlob } from '../src';
|
||||
|
||||
describe('download()', () => {
|
||||
let warningMessages: string[];
|
||||
const originalConsoleWarn = console.warn;
|
||||
beforeEach(() => {
|
||||
warningMessages = [];
|
||||
console.warn = m => {
|
||||
warningMessages.push(m);
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
console.warn = originalConsoleWarn;
|
||||
});
|
||||
|
||||
it('should re-create FileFsRef symlinks properly', async () => {
|
||||
if (process.platform === 'win32') {
|
||||
console.log('Skipping test on windows');
|
||||
return;
|
||||
}
|
||||
const files = await glob('**', path.join(__dirname, 'symlinks'));
|
||||
assert.equal(Object.keys(files).length, 4);
|
||||
|
||||
const outDir = path.join(__dirname, 'symlinks-out');
|
||||
await fs.remove(outDir);
|
||||
|
||||
const files2 = await download(files, outDir);
|
||||
assert.equal(Object.keys(files2).length, 4);
|
||||
|
||||
const [linkStat, linkDirStat, aStat] = await Promise.all([
|
||||
fs.lstat(path.join(outDir, 'link.txt')),
|
||||
fs.lstat(path.join(outDir, 'link-dir')),
|
||||
fs.lstat(path.join(outDir, 'a.txt')),
|
||||
]);
|
||||
assert(linkStat.isSymbolicLink());
|
||||
assert(linkDirStat.isSymbolicLink());
|
||||
assert(aStat.isFile());
|
||||
|
||||
const [linkDirContents, linkTextContents] = await Promise.all([
|
||||
readlink(path.join(outDir, 'link-dir')),
|
||||
readlink(path.join(outDir, 'link.txt')),
|
||||
]);
|
||||
|
||||
strictEqual(linkDirContents, 'dir');
|
||||
strictEqual(linkTextContents, './a.txt');
|
||||
});
|
||||
|
||||
it('should re-create FileBlob symlinks properly', async () => {
|
||||
if (process.platform === 'win32') {
|
||||
console.log('Skipping test on windows');
|
||||
return;
|
||||
}
|
||||
|
||||
const files = {
|
||||
'a.txt': new FileBlob({
|
||||
mode: 33188,
|
||||
contentType: undefined,
|
||||
data: 'a text',
|
||||
}),
|
||||
'dir/b.txt': new FileBlob({
|
||||
mode: 33188,
|
||||
contentType: undefined,
|
||||
data: 'b text',
|
||||
}),
|
||||
'link-dir': new FileBlob({
|
||||
mode: 41453,
|
||||
contentType: undefined,
|
||||
data: 'dir',
|
||||
}),
|
||||
'link.txt': new FileBlob({
|
||||
mode: 41453,
|
||||
contentType: undefined,
|
||||
data: 'a.txt',
|
||||
}),
|
||||
};
|
||||
|
||||
strictEqual(Object.keys(files).length, 4);
|
||||
|
||||
const outDir = path.join(__dirname, 'symlinks-out');
|
||||
await fs.remove(outDir);
|
||||
|
||||
const files2 = await download(files, outDir);
|
||||
strictEqual(Object.keys(files2).length, 4);
|
||||
|
||||
const [linkStat, linkDirStat, aStat, dirStat] = await Promise.all([
|
||||
fs.lstat(path.join(outDir, 'link.txt')),
|
||||
fs.lstat(path.join(outDir, 'link-dir')),
|
||||
fs.lstat(path.join(outDir, 'a.txt')),
|
||||
fs.lstat(path.join(outDir, 'dir')),
|
||||
]);
|
||||
|
||||
assert(linkStat.isSymbolicLink());
|
||||
assert(linkDirStat.isSymbolicLink());
|
||||
assert(aStat.isFile());
|
||||
assert(dirStat.isDirectory());
|
||||
|
||||
const [linkDirContents, linkTextContents] = await Promise.all([
|
||||
readlink(path.join(outDir, 'link-dir')),
|
||||
readlink(path.join(outDir, 'link.txt')),
|
||||
]);
|
||||
|
||||
strictEqual(linkDirContents, 'dir');
|
||||
strictEqual(linkTextContents, 'a.txt');
|
||||
});
|
||||
|
||||
it('should download symlinks even with incorrect file', async () => {
|
||||
if (process.platform === 'win32') {
|
||||
console.log('Skipping test on windows');
|
||||
return;
|
||||
}
|
||||
const files = {
|
||||
'dir/file.txt': new FileBlob({
|
||||
mode: 33188,
|
||||
contentType: undefined,
|
||||
data: 'file text',
|
||||
}),
|
||||
linkdir: new FileBlob({
|
||||
mode: 41453,
|
||||
contentType: undefined,
|
||||
data: 'dir',
|
||||
}),
|
||||
'linkdir/file.txt': new FileBlob({
|
||||
mode: 33188,
|
||||
contentType: undefined,
|
||||
data: 'this file should be discarded',
|
||||
}),
|
||||
};
|
||||
|
||||
const outDir = path.join(__dirname, 'symlinks-out');
|
||||
await fs.remove(outDir);
|
||||
await fs.mkdirp(outDir);
|
||||
|
||||
await download(files, outDir);
|
||||
|
||||
const [dir, file, linkdir] = await Promise.all([
|
||||
fs.lstat(path.join(outDir, 'dir')),
|
||||
fs.lstat(path.join(outDir, 'dir/file.txt')),
|
||||
fs.lstat(path.join(outDir, 'linkdir')),
|
||||
]);
|
||||
expect(dir.isFile()).toBe(false);
|
||||
expect(dir.isSymbolicLink()).toBe(false);
|
||||
|
||||
expect(file.isFile()).toBe(true);
|
||||
expect(file.isSymbolicLink()).toBe(false);
|
||||
|
||||
expect(linkdir.isSymbolicLink()).toBe(true);
|
||||
|
||||
expect(warningMessages).toEqual([
|
||||
'Warning: file "linkdir/file.txt" is within a symlinked directory "linkdir" and will be ignored',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should create empty directory entries', async () => {
|
||||
const outDir = path.join(__dirname, 'symlinks-out');
|
||||
await fs.remove(outDir);
|
||||
const files = {
|
||||
'empty-dir': new FileBlob({
|
||||
mode: 16877,
|
||||
contentType: undefined,
|
||||
data: '',
|
||||
}),
|
||||
dir: new FileBlob({
|
||||
mode: 16877,
|
||||
contentType: undefined,
|
||||
data: '',
|
||||
}),
|
||||
'dir/subdir': new FileBlob({
|
||||
mode: 16877,
|
||||
contentType: undefined,
|
||||
data: '',
|
||||
}),
|
||||
'another/subdir': new FileBlob({
|
||||
mode: 16877,
|
||||
contentType: undefined,
|
||||
data: '',
|
||||
}),
|
||||
};
|
||||
|
||||
await download(files, outDir);
|
||||
|
||||
const stats = await Promise.all([
|
||||
fs.lstat(path.join(outDir, 'empty-dir')),
|
||||
fs.lstat(path.join(outDir, 'dir')),
|
||||
fs.lstat(path.join(outDir, 'dir/subdir')),
|
||||
fs.lstat(path.join(outDir, 'another/subdir')),
|
||||
]);
|
||||
for (const stat of stats) {
|
||||
expect(stat.isDirectory()).toEqual(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
43
packages/build-utils/test/unit.glob.test.ts
vendored
Normal file
43
packages/build-utils/test/unit.glob.test.ts
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
import fs from 'fs-extra';
|
||||
import { join } from 'path';
|
||||
import { tmpdir } from 'os';
|
||||
import { glob } from '../src';
|
||||
|
||||
function isDirectory(mode: number): boolean {
|
||||
const stat = new fs.Stats();
|
||||
stat.mode = mode;
|
||||
return stat.isDirectory();
|
||||
}
|
||||
|
||||
describe('glob()', () => {
|
||||
it('should return entries for empty directories', async () => {
|
||||
const dir = await fs.mkdtemp(join(tmpdir(), 'build-utils-test'));
|
||||
try {
|
||||
await Promise.all([
|
||||
fs.writeFile(join(dir, 'root.txt'), 'file at the root'),
|
||||
fs.mkdirp(join(dir, 'empty-dir')),
|
||||
fs
|
||||
.mkdirp(join(dir, 'dir-with-file'))
|
||||
.then(() =>
|
||||
fs.writeFile(join(dir, 'dir-with-file/data.json'), '{"a":"b"}')
|
||||
),
|
||||
fs.mkdirp(join(dir, 'another/subdir')),
|
||||
]);
|
||||
const files = await glob('**', dir);
|
||||
const fileNames = Object.keys(files).sort();
|
||||
expect(fileNames).toHaveLength(4);
|
||||
expect(fileNames).toEqual([
|
||||
'another/subdir',
|
||||
'dir-with-file/data.json',
|
||||
'empty-dir',
|
||||
'root.txt',
|
||||
]);
|
||||
expect(isDirectory(files['another/subdir'].mode)).toEqual(true);
|
||||
expect(isDirectory(files['empty-dir'].mode)).toEqual(true);
|
||||
expect(isDirectory(files['dir-with-file/data.json'].mode)).toEqual(false);
|
||||
expect(isDirectory(files['root.txt'].mode)).toEqual(false);
|
||||
} finally {
|
||||
await fs.remove(dir);
|
||||
}
|
||||
});
|
||||
});
|
||||
143
packages/build-utils/test/unit.test.ts
vendored
143
packages/build-utils/test/unit.test.ts
vendored
@@ -1,10 +1,9 @@
|
||||
import ms from 'ms';
|
||||
import path from 'path';
|
||||
import fs, { readlink } from 'fs-extra';
|
||||
import { strict as assert, strictEqual } from 'assert';
|
||||
import fs from 'fs-extra';
|
||||
import { strict as assert } from 'assert';
|
||||
import { createZip } from '../src/lambda';
|
||||
import { getSupportedNodeVersion } from '../src/fs/node-version';
|
||||
import download from '../src/fs/download';
|
||||
import {
|
||||
glob,
|
||||
spawnAsync,
|
||||
@@ -14,7 +13,6 @@ import {
|
||||
runNpmInstall,
|
||||
runPackageJsonScript,
|
||||
scanParentDirs,
|
||||
FileBlob,
|
||||
Prerender,
|
||||
} from '../src';
|
||||
|
||||
@@ -51,96 +49,6 @@ afterEach(() => {
|
||||
console.warn = originalConsoleWarn;
|
||||
});
|
||||
|
||||
it('should re-create FileFsRef symlinks properly', async () => {
|
||||
if (process.platform === 'win32') {
|
||||
console.log('Skipping test on windows');
|
||||
return;
|
||||
}
|
||||
const files = await glob('**', path.join(__dirname, 'symlinks'));
|
||||
assert.equal(Object.keys(files).length, 4);
|
||||
|
||||
const outDir = path.join(__dirname, 'symlinks-out');
|
||||
await fs.remove(outDir);
|
||||
|
||||
const files2 = await download(files, outDir);
|
||||
assert.equal(Object.keys(files2).length, 4);
|
||||
|
||||
const [linkStat, linkDirStat, aStat] = await Promise.all([
|
||||
fs.lstat(path.join(outDir, 'link.txt')),
|
||||
fs.lstat(path.join(outDir, 'link-dir')),
|
||||
fs.lstat(path.join(outDir, 'a.txt')),
|
||||
]);
|
||||
assert(linkStat.isSymbolicLink());
|
||||
assert(linkDirStat.isSymbolicLink());
|
||||
assert(aStat.isFile());
|
||||
|
||||
const [linkDirContents, linkTextContents] = await Promise.all([
|
||||
readlink(path.join(outDir, 'link-dir')),
|
||||
readlink(path.join(outDir, 'link.txt')),
|
||||
]);
|
||||
|
||||
strictEqual(linkDirContents, 'dir');
|
||||
strictEqual(linkTextContents, './a.txt');
|
||||
});
|
||||
|
||||
it('should re-create FileBlob symlinks properly', async () => {
|
||||
if (process.platform === 'win32') {
|
||||
console.log('Skipping test on windows');
|
||||
return;
|
||||
}
|
||||
|
||||
const files = {
|
||||
'a.txt': new FileBlob({
|
||||
mode: 33188,
|
||||
contentType: undefined,
|
||||
data: 'a text',
|
||||
}),
|
||||
'dir/b.txt': new FileBlob({
|
||||
mode: 33188,
|
||||
contentType: undefined,
|
||||
data: 'b text',
|
||||
}),
|
||||
'link-dir': new FileBlob({
|
||||
mode: 41453,
|
||||
contentType: undefined,
|
||||
data: 'dir',
|
||||
}),
|
||||
'link.txt': new FileBlob({
|
||||
mode: 41453,
|
||||
contentType: undefined,
|
||||
data: 'a.txt',
|
||||
}),
|
||||
};
|
||||
|
||||
strictEqual(Object.keys(files).length, 4);
|
||||
|
||||
const outDir = path.join(__dirname, 'symlinks-out');
|
||||
await fs.remove(outDir);
|
||||
|
||||
const files2 = await download(files, outDir);
|
||||
strictEqual(Object.keys(files2).length, 4);
|
||||
|
||||
const [linkStat, linkDirStat, aStat, dirStat] = await Promise.all([
|
||||
fs.lstat(path.join(outDir, 'link.txt')),
|
||||
fs.lstat(path.join(outDir, 'link-dir')),
|
||||
fs.lstat(path.join(outDir, 'a.txt')),
|
||||
fs.lstat(path.join(outDir, 'dir')),
|
||||
]);
|
||||
|
||||
assert(linkStat.isSymbolicLink());
|
||||
assert(linkDirStat.isSymbolicLink());
|
||||
assert(aStat.isFile());
|
||||
assert(dirStat.isDirectory());
|
||||
|
||||
const [linkDirContents, linkTextContents] = await Promise.all([
|
||||
readlink(path.join(outDir, 'link-dir')),
|
||||
readlink(path.join(outDir, 'link.txt')),
|
||||
]);
|
||||
|
||||
strictEqual(linkDirContents, 'dir');
|
||||
strictEqual(linkTextContents, 'a.txt');
|
||||
});
|
||||
|
||||
it('should create zip files with symlinks properly', async () => {
|
||||
if (process.platform === 'win32') {
|
||||
console.log('Skipping test on windows');
|
||||
@@ -169,53 +77,6 @@ it('should create zip files with symlinks properly', async () => {
|
||||
assert(aStat.isFile());
|
||||
});
|
||||
|
||||
it('should download symlinks even with incorrect file', async () => {
|
||||
if (process.platform === 'win32') {
|
||||
console.log('Skipping test on windows');
|
||||
return;
|
||||
}
|
||||
const files = {
|
||||
'dir/file.txt': new FileBlob({
|
||||
mode: 33188,
|
||||
contentType: undefined,
|
||||
data: 'file text',
|
||||
}),
|
||||
linkdir: new FileBlob({
|
||||
mode: 41453,
|
||||
contentType: undefined,
|
||||
data: 'dir',
|
||||
}),
|
||||
'linkdir/file.txt': new FileBlob({
|
||||
mode: 33188,
|
||||
contentType: undefined,
|
||||
data: 'this file should be discarded',
|
||||
}),
|
||||
};
|
||||
|
||||
const outDir = path.join(__dirname, 'symlinks-out');
|
||||
await fs.remove(outDir);
|
||||
await fs.mkdirp(outDir);
|
||||
|
||||
await download(files, outDir);
|
||||
|
||||
const [dir, file, linkdir] = await Promise.all([
|
||||
fs.lstat(path.join(outDir, 'dir')),
|
||||
fs.lstat(path.join(outDir, 'dir/file.txt')),
|
||||
fs.lstat(path.join(outDir, 'linkdir')),
|
||||
]);
|
||||
expect(dir.isFile()).toBe(false);
|
||||
expect(dir.isSymbolicLink()).toBe(false);
|
||||
|
||||
expect(file.isFile()).toBe(true);
|
||||
expect(file.isSymbolicLink()).toBe(false);
|
||||
|
||||
expect(linkdir.isSymbolicLink()).toBe(true);
|
||||
|
||||
expect(warningMessages).toEqual([
|
||||
'Warning: file "linkdir/file.txt" is within a symlinked directory "linkdir" and will be ignored',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should only match supported node versions, otherwise throw an error', async () => {
|
||||
expect(await getSupportedNodeVersion('14.x', false)).toHaveProperty(
|
||||
'major',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vercel",
|
||||
"version": "28.9.0",
|
||||
"version": "28.10.1",
|
||||
"preferGlobal": true,
|
||||
"license": "Apache-2.0",
|
||||
"description": "The command-line interface for Vercel",
|
||||
@@ -41,16 +41,16 @@
|
||||
"node": ">= 14"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/build-utils": "5.7.1",
|
||||
"@vercel/go": "2.2.20",
|
||||
"@vercel/hydrogen": "0.0.34",
|
||||
"@vercel/next": "3.3.3",
|
||||
"@vercel/node": "2.8.1",
|
||||
"@vercel/python": "3.1.30",
|
||||
"@vercel/redwood": "1.0.40",
|
||||
"@vercel/remix": "1.1.2",
|
||||
"@vercel/ruby": "1.3.46",
|
||||
"@vercel/static-build": "1.0.43",
|
||||
"@vercel/build-utils": "5.7.2",
|
||||
"@vercel/go": "2.2.21",
|
||||
"@vercel/hydrogen": "0.0.35",
|
||||
"@vercel/next": "3.3.5",
|
||||
"@vercel/node": "2.8.2",
|
||||
"@vercel/python": "3.1.31",
|
||||
"@vercel/redwood": "1.0.41",
|
||||
"@vercel/remix": "1.1.3",
|
||||
"@vercel/ruby": "1.3.47",
|
||||
"@vercel/static-build": "1.0.44",
|
||||
"update-notifier": "5.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -60,8 +60,6 @@
|
||||
"@sindresorhus/slugify": "0.11.0",
|
||||
"@swc/core": "1.2.218",
|
||||
"@tootallnate/once": "1.1.2",
|
||||
"@types/ansi-escapes": "3.0.0",
|
||||
"@types/ansi-regex": "4.0.0",
|
||||
"@types/async-retry": "1.2.1",
|
||||
"@types/bytes": "3.0.0",
|
||||
"@types/chance": "1.1.3",
|
||||
@@ -95,17 +93,17 @@
|
||||
"@types/which": "1.3.2",
|
||||
"@types/write-json-file": "2.2.1",
|
||||
"@types/yauzl-promise": "2.1.0",
|
||||
"@vercel/client": "12.2.22",
|
||||
"@vercel/client": "12.2.23",
|
||||
"@vercel/error-utils": "1.0.3",
|
||||
"@vercel/frameworks": "1.1.15",
|
||||
"@vercel/fs-detectors": "3.5.5",
|
||||
"@vercel/frameworks": "1.1.16",
|
||||
"@vercel/fs-detectors": "3.5.6",
|
||||
"@vercel/fun": "1.0.4",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"@zeit/source-map-support": "0.6.2",
|
||||
"ajv": "6.12.2",
|
||||
"alpha-sort": "2.0.1",
|
||||
"ansi-escapes": "3.0.0",
|
||||
"ansi-regex": "3.0.0",
|
||||
"ansi-escapes": "4.3.2",
|
||||
"ansi-regex": "5.0.1",
|
||||
"arg": "5.0.0",
|
||||
"async-listen": "1.2.0",
|
||||
"async-retry": "1.1.3",
|
||||
@@ -161,8 +159,9 @@
|
||||
"rimraf": "3.0.2",
|
||||
"semver": "5.5.0",
|
||||
"serve-handler": "6.1.1",
|
||||
"strip-ansi": "5.2.0",
|
||||
"strip-ansi": "6.0.1",
|
||||
"stripe": "5.1.0",
|
||||
"supports-hyperlinks": "2.2.0",
|
||||
"tar-fs": "1.16.3",
|
||||
"test-listen": "1.1.0",
|
||||
"text-table": "0.2.0",
|
||||
|
||||
@@ -88,6 +88,9 @@ async function performCreateAlias(
|
||||
if (err.code === 'invalid_alias') {
|
||||
return new ERRORS.InvalidAlias(alias);
|
||||
}
|
||||
if (err.code === 'deployment_not_ready') {
|
||||
return new ERRORS.DeploymentNotReady({ url: deployment.url });
|
||||
}
|
||||
if (err.status === 403) {
|
||||
if (err.code === 'alias_in_use') {
|
||||
return new ERRORS.AliasInUse(alias);
|
||||
@@ -96,9 +99,6 @@ async function performCreateAlias(
|
||||
return new ERRORS.DomainPermissionDenied(alias, contextName);
|
||||
}
|
||||
}
|
||||
if (err.status === 400) {
|
||||
return new ERRORS.DeploymentNotReady({ url: deployment.url });
|
||||
}
|
||||
}
|
||||
|
||||
throw err;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import chalk from 'chalk';
|
||||
import * as ansiEscapes from 'ansi-escapes';
|
||||
import { supportsHyperlink as detectSupportsHyperlink } from 'supports-hyperlinks';
|
||||
import renderLink from './link';
|
||||
import wait, { StopSpinner } from './wait';
|
||||
import type { WritableTTY } from '../../types';
|
||||
@@ -8,24 +10,34 @@ const IS_TEST = process.env.NODE_ENV === 'test';
|
||||
|
||||
export interface OutputOptions {
|
||||
debug?: boolean;
|
||||
supportsHyperlink?: boolean;
|
||||
}
|
||||
|
||||
export interface LogOptions {
|
||||
color?: typeof chalk;
|
||||
}
|
||||
|
||||
interface LinkOptions {
|
||||
fallback?: false | (() => string);
|
||||
}
|
||||
|
||||
export class Output {
|
||||
stream: WritableTTY;
|
||||
debugEnabled: boolean;
|
||||
supportsHyperlink: boolean;
|
||||
private spinnerMessage: string;
|
||||
private _spinner: StopSpinner | null;
|
||||
|
||||
constructor(
|
||||
stream: WritableTTY,
|
||||
{ debug: debugEnabled = false }: OutputOptions = {}
|
||||
{
|
||||
debug: debugEnabled = false,
|
||||
supportsHyperlink = detectSupportsHyperlink(stream),
|
||||
}: OutputOptions = {}
|
||||
) {
|
||||
this.stream = stream;
|
||||
this.debugEnabled = debugEnabled;
|
||||
this.supportsHyperlink = supportsHyperlink;
|
||||
this.spinnerMessage = '';
|
||||
this._spinner = null;
|
||||
}
|
||||
@@ -167,4 +179,27 @@ export class Output {
|
||||
|
||||
return promise;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an ANSI formatted hyperlink when support has been enabled.
|
||||
*/
|
||||
link = (
|
||||
text: string,
|
||||
url: string,
|
||||
{ fallback }: LinkOptions = {}
|
||||
): string => {
|
||||
// Based on https://github.com/sindresorhus/terminal-link (MIT license)
|
||||
if (!this.supportsHyperlink) {
|
||||
// If the fallback has been explicitly disabled, don't modify the text itself
|
||||
if (fallback === false) {
|
||||
return renderLink(text);
|
||||
}
|
||||
|
||||
return typeof fallback === 'function'
|
||||
? fallback()
|
||||
: `${text} (${renderLink(url)})`;
|
||||
}
|
||||
|
||||
return ansiEscapes.link(chalk.cyan(text), url);
|
||||
};
|
||||
}
|
||||
|
||||
37
packages/cli/test/unit/util/output/create-output.test.ts
Normal file
37
packages/cli/test/unit/util/output/create-output.test.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import stripAnsi from 'strip-ansi';
|
||||
import { client } from '../../../mocks/client';
|
||||
|
||||
describe('Output', () => {
|
||||
describe('link()', () => {
|
||||
it('should return hyperlink ANSI codes when `supportsHyperlink=true`', () => {
|
||||
client.output.supportsHyperlink = true;
|
||||
const val = client.output.link('Click Here', 'https://example.com');
|
||||
expect(val).toEqual(
|
||||
'\x1B]8;;https://example.com\x07Click Here\x1B]8;;\x07'
|
||||
);
|
||||
expect(stripAnsi(val)).toEqual('Click Here');
|
||||
});
|
||||
|
||||
it('should return default fallback when `supportsHyperlink=false`', () => {
|
||||
client.output.supportsHyperlink = false;
|
||||
const val = client.output.link('Click Here', 'https://example.com');
|
||||
expect(val).toEqual('Click Here (https://example.com)');
|
||||
});
|
||||
|
||||
it('should return text fallback when `supportsHyperlink=false` with `fallback: false`', () => {
|
||||
client.output.supportsHyperlink = false;
|
||||
const val = client.output.link('Click Here', 'https://example.com', {
|
||||
fallback: false,
|
||||
});
|
||||
expect(val).toEqual('Click Here');
|
||||
});
|
||||
|
||||
it('should return fallback when `supportsHyperlink=false` with `fallback` function', () => {
|
||||
client.output.supportsHyperlink = false;
|
||||
const val = client.output.link('Click Here', 'https://example.com', {
|
||||
fallback: () => 'other',
|
||||
});
|
||||
expect(val).toEqual('other');
|
||||
});
|
||||
});
|
||||
});
|
||||
4
packages/cli/types/supports-hyperlinks/index.d.ts
vendored
Normal file
4
packages/cli/types/supports-hyperlinks/index.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
declare module 'supports-hyperlinks' {
|
||||
import { Writable } from 'stream';
|
||||
export function supportsHyperlink(stream: Writable): boolean;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/client",
|
||||
"version": "12.2.22",
|
||||
"version": "12.2.23",
|
||||
"main": "dist/index.js",
|
||||
"typings": "dist/index.d.ts",
|
||||
"homepage": "https://vercel.com",
|
||||
@@ -43,7 +43,7 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/build-utils": "5.7.1",
|
||||
"@vercel/build-utils": "5.7.2",
|
||||
"@vercel/routing-utils": "2.1.3",
|
||||
"@zeit/fetch": "5.2.0",
|
||||
"async-retry": "1.2.3",
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
- [geolocation](README.md#geolocation)
|
||||
- [ipAddress](README.md#ipaddress)
|
||||
- [json](README.md#json)
|
||||
- [next](README.md#next)
|
||||
- [rewrite](README.md#rewrite)
|
||||
|
||||
@@ -169,6 +170,49 @@ Returns the IP address of the request from the headers.
|
||||
|
||||
---
|
||||
|
||||
### json
|
||||
|
||||
▸ **json**(`data`, `init?`): `Response`
|
||||
|
||||
Builds a response object from a serializable JavaScript object:
|
||||
|
||||
- sets the 'Content-Type' response header to 'application/json'
|
||||
- sets the response body from provided data
|
||||
|
||||
**`See`**
|
||||
|
||||
[https://fetch.spec.whatwg.org/#dom-response-json](https://fetch.spec.whatwg.org/#dom-response-json)
|
||||
|
||||
**`Example`**
|
||||
|
||||
<caption>Building a JSON response</caption>
|
||||
|
||||
```ts
|
||||
import { json } from '@vercel/edge';
|
||||
|
||||
const response = json(
|
||||
{ notification: { success: true, content: 'worked' } },
|
||||
{ headers: { 'x-custom': '1' } }
|
||||
);
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| :------ | :------------- | :------------------------------------------------------ |
|
||||
| `data` | `any` | serialized data |
|
||||
| `init?` | `ResponseInit` | optional custom response status, statusText and headers |
|
||||
|
||||
#### Returns
|
||||
|
||||
`Response`
|
||||
|
||||
#### Defined in
|
||||
|
||||
[src/response.ts:19](https://github.com/vercel/vercel/blob/main/packages/edge/src/response.ts#L19)
|
||||
|
||||
---
|
||||
|
||||
### next
|
||||
|
||||
▸ **next**(`init?`): `Response`
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/edge",
|
||||
"version": "0.1.2",
|
||||
"version": "0.2.1",
|
||||
"license": "MIT",
|
||||
"main": "dist/index.js",
|
||||
"module": "dist/index.mjs",
|
||||
|
||||
@@ -3,3 +3,6 @@ export * from './middleware-helpers';
|
||||
|
||||
export type { Geo } from './edge-headers';
|
||||
export * from './edge-headers';
|
||||
export * from './response';
|
||||
|
||||
import './published-types.d.ts';
|
||||
|
||||
8
packages/edge/src/published-types.d.ts
vendored
Normal file
8
packages/edge/src/published-types.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
/* eslint-disable no-var */
|
||||
|
||||
declare global {
|
||||
// must be `var` to work
|
||||
var process: {
|
||||
env: Record<string, string>;
|
||||
};
|
||||
}
|
||||
22
packages/edge/src/response.ts
Normal file
22
packages/edge/src/response.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Builds a response object from a serializable JavaScript object:
|
||||
* - sets the 'Content-Type' response header to 'application/json'
|
||||
* - sets the response body from provided data
|
||||
*
|
||||
* @see {@link https://fetch.spec.whatwg.org/#dom-response-json}
|
||||
* @param data serialized data
|
||||
* @param init optional custom response status, statusText and headers
|
||||
*
|
||||
* @example
|
||||
* <caption>Building a JSON response</caption>
|
||||
*
|
||||
* ```ts
|
||||
* import { json } from '@vercel/edge';
|
||||
*
|
||||
* const response = json({ notification: { success: true, content: 'worked' } }, { headers: {'x-custom': '1' }})
|
||||
* ```
|
||||
*/
|
||||
export function json(data: any, init?: ResponseInit): Response {
|
||||
// @ts-expect-error This is not in lib/dom right now, and we can't augment it.
|
||||
return Response.json(data, init);
|
||||
}
|
||||
34
packages/edge/test/response.test.ts
vendored
Normal file
34
packages/edge/test/response.test.ts
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* @jest-environment @edge-runtime/jest-environment
|
||||
*/
|
||||
|
||||
import { json } from '../src/response';
|
||||
|
||||
describe('json', () => {
|
||||
it('returns a response with JSON content', async () => {
|
||||
const content = { foo: 'bar' };
|
||||
const response = json(content);
|
||||
expect(response.headers.get('content-type')).toEqual('application/json');
|
||||
expect(await response.json()).toEqual(content);
|
||||
});
|
||||
|
||||
it('can set response init', async () => {
|
||||
const content = { bar: 'baz' };
|
||||
const status = 201;
|
||||
const statusText = 'it is in';
|
||||
const customHeader = 'x-custom';
|
||||
const customHeaderValue = '1';
|
||||
const response = json(content, {
|
||||
status,
|
||||
statusText,
|
||||
headers: { [customHeader]: customHeaderValue },
|
||||
});
|
||||
expect(response).toMatchObject({
|
||||
status,
|
||||
statusText,
|
||||
});
|
||||
expect(response.headers.get('content-type')).toEqual('application/json');
|
||||
expect(response.headers.get(customHeader)).toEqual(customHeaderValue);
|
||||
expect(await response.json()).toEqual(content);
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/frameworks",
|
||||
"version": "1.1.15",
|
||||
"version": "1.1.16",
|
||||
"main": "./dist/frameworks.js",
|
||||
"types": "./dist/frameworks.d.ts",
|
||||
"files": [
|
||||
|
||||
@@ -1790,7 +1790,7 @@ export const frameworks = [
|
||||
value: 'docs/.vitepress/dist',
|
||||
},
|
||||
},
|
||||
getOutputDirName: async () => '.vitepress/dist',
|
||||
getOutputDirName: async () => 'docs/.vitepress/dist',
|
||||
},
|
||||
{
|
||||
name: 'VuePress',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/fs-detectors",
|
||||
"version": "3.5.5",
|
||||
"version": "3.5.6",
|
||||
"description": "Vercel filesystem detectors",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -20,7 +20,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/error-utils": "1.0.3",
|
||||
"@vercel/frameworks": "1.1.15",
|
||||
"@vercel/frameworks": "1.1.16",
|
||||
"@vercel/routing-utils": "2.1.3",
|
||||
"glob": "8.0.3",
|
||||
"js-yaml": "4.1.0",
|
||||
@@ -35,7 +35,7 @@
|
||||
"@types/minimatch": "3.0.5",
|
||||
"@types/node": "14.18.33",
|
||||
"@types/semver": "7.3.10",
|
||||
"@vercel/build-utils": "5.7.1",
|
||||
"@vercel/build-utils": "5.7.2",
|
||||
"typescript": "4.3.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/go",
|
||||
"version": "2.2.20",
|
||||
"version": "2.2.21",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/go",
|
||||
@@ -35,7 +35,7 @@
|
||||
"@types/jest": "28.1.6",
|
||||
"@types/node-fetch": "^2.3.0",
|
||||
"@types/tar": "^4.0.0",
|
||||
"@vercel/build-utils": "5.7.1",
|
||||
"@vercel/build-utils": "5.7.2",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"async-retry": "1.3.1",
|
||||
"execa": "^1.0.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/hydrogen",
|
||||
"version": "0.0.34",
|
||||
"version": "0.0.35",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
"homepage": "https://vercel.com/docs",
|
||||
@@ -21,7 +21,7 @@
|
||||
"devDependencies": {
|
||||
"@types/jest": "27.5.1",
|
||||
"@types/node": "14.18.33",
|
||||
"@vercel/build-utils": "5.7.1",
|
||||
"@vercel/build-utils": "5.7.2",
|
||||
"@vercel/static-config": "2.0.6",
|
||||
"typescript": "4.6.4"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/next",
|
||||
"version": "3.3.3",
|
||||
"version": "3.3.5",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/next-js",
|
||||
@@ -45,7 +45,7 @@
|
||||
"@types/semver": "6.0.0",
|
||||
"@types/text-table": "0.2.1",
|
||||
"@types/webpack-sources": "3.2.0",
|
||||
"@vercel/build-utils": "5.7.1",
|
||||
"@vercel/build-utils": "5.7.2",
|
||||
"@vercel/nft": "0.22.1",
|
||||
"@vercel/routing-utils": "2.1.3",
|
||||
"async-sema": "3.0.1",
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
PrepareCache,
|
||||
NodejsLambda,
|
||||
BuildResultV2Typical as BuildResult,
|
||||
BuildResultBuildOutput,
|
||||
} from '@vercel/build-utils';
|
||||
import { Route, RouteWithHandle, RouteWithSrc } from '@vercel/routing-utils';
|
||||
import {
|
||||
@@ -65,6 +66,7 @@ import {
|
||||
getExportIntent,
|
||||
getExportStatus,
|
||||
getFilesMapFromReasons,
|
||||
getImagesConfig,
|
||||
getImagesManifest,
|
||||
getMiddlewareManifest,
|
||||
getNextConfig,
|
||||
@@ -453,6 +455,24 @@ export const build: BuildV2 = async ({
|
||||
}
|
||||
debug('build command exited');
|
||||
|
||||
let buildOutputVersion: undefined | number;
|
||||
|
||||
try {
|
||||
const data = await readJSON(
|
||||
path.join(outputDirectory, 'output/config.json')
|
||||
);
|
||||
buildOutputVersion = data.version;
|
||||
} catch (_) {
|
||||
// tolerate for older versions
|
||||
}
|
||||
|
||||
if (buildOutputVersion) {
|
||||
return {
|
||||
buildOutputPath: path.join(outputDirectory, 'output'),
|
||||
buildOutputVersion,
|
||||
} as BuildResultBuildOutput;
|
||||
}
|
||||
|
||||
let appMountPrefixNoTrailingSlash = path.posix
|
||||
.join('/', entryDirectory)
|
||||
.replace(/\/+$/, '');
|
||||
@@ -802,18 +822,7 @@ export const build: BuildV2 = async ({
|
||||
|
||||
return {
|
||||
output,
|
||||
images:
|
||||
imagesManifest?.images?.loader === 'default'
|
||||
? {
|
||||
domains: imagesManifest.images.domains,
|
||||
sizes: imagesManifest.images.sizes,
|
||||
remotePatterns: imagesManifest.images.remotePatterns,
|
||||
minimumCacheTTL: imagesManifest.images.minimumCacheTTL,
|
||||
dangerouslyAllowSVG: imagesManifest.images.dangerouslyAllowSVG,
|
||||
contentSecurityPolicy:
|
||||
imagesManifest.images.contentSecurityPolicy,
|
||||
}
|
||||
: undefined,
|
||||
images: getImagesConfig(imagesManifest),
|
||||
routes: [
|
||||
...privateOutputs.routes,
|
||||
|
||||
@@ -2170,17 +2179,7 @@ export const build: BuildV2 = async ({
|
||||
...privateOutputs.files,
|
||||
},
|
||||
wildcard: wildcardConfig,
|
||||
images:
|
||||
imagesManifest?.images?.loader === 'default'
|
||||
? {
|
||||
domains: imagesManifest.images.domains,
|
||||
sizes: imagesManifest.images.sizes,
|
||||
remotePatterns: imagesManifest.images.remotePatterns,
|
||||
minimumCacheTTL: imagesManifest.images.minimumCacheTTL,
|
||||
dangerouslyAllowSVG: imagesManifest.images.dangerouslyAllowSVG,
|
||||
contentSecurityPolicy: imagesManifest.images.contentSecurityPolicy,
|
||||
}
|
||||
: undefined,
|
||||
images: getImagesConfig(imagesManifest),
|
||||
/*
|
||||
Desired routes order
|
||||
- Runtime headers
|
||||
|
||||
@@ -38,6 +38,7 @@ import {
|
||||
outputFunctionFileSizeInfo,
|
||||
MAX_UNCOMPRESSED_LAMBDA_SIZE,
|
||||
normalizeIndexOutput,
|
||||
getImagesConfig,
|
||||
getNextServerPath,
|
||||
getMiddlewareBundle,
|
||||
getFilesMapFromReasons,
|
||||
@@ -1158,18 +1159,7 @@ export async function serverBuild({
|
||||
|
||||
return {
|
||||
wildcard: wildcardConfig,
|
||||
images:
|
||||
imagesManifest?.images?.loader === 'default'
|
||||
? {
|
||||
domains: imagesManifest.images.domains,
|
||||
sizes: imagesManifest.images.sizes,
|
||||
remotePatterns: imagesManifest.images.remotePatterns,
|
||||
minimumCacheTTL: imagesManifest.images.minimumCacheTTL,
|
||||
formats: imagesManifest.images.formats,
|
||||
dangerouslyAllowSVG: imagesManifest.images.dangerouslyAllowSVG,
|
||||
contentSecurityPolicy: imagesManifest.images.contentSecurityPolicy,
|
||||
}
|
||||
: undefined,
|
||||
images: getImagesConfig(imagesManifest),
|
||||
output: {
|
||||
...publicDirectoryFiles,
|
||||
...lambdas,
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
isSymbolicLink,
|
||||
NodejsLambda,
|
||||
EdgeFunction,
|
||||
Images,
|
||||
} from '@vercel/build-utils';
|
||||
import { NodeFileTraceReasons } from '@vercel/nft';
|
||||
import type {
|
||||
@@ -155,6 +156,23 @@ async function getNextConfig(workPath: string, entryPath: string) {
|
||||
return null;
|
||||
}
|
||||
|
||||
function getImagesConfig(
|
||||
imagesManifest: NextImagesManifest | undefined
|
||||
): Images | undefined {
|
||||
return imagesManifest?.images?.loader === 'default' &&
|
||||
imagesManifest.images?.unoptimized !== true
|
||||
? {
|
||||
domains: imagesManifest.images.domains,
|
||||
sizes: imagesManifest.images.sizes,
|
||||
remotePatterns: imagesManifest.images.remotePatterns,
|
||||
minimumCacheTTL: imagesManifest.images.minimumCacheTTL,
|
||||
formats: imagesManifest.images.formats,
|
||||
dangerouslyAllowSVG: imagesManifest.images.dangerouslyAllowSVG,
|
||||
contentSecurityPolicy: imagesManifest.images.contentSecurityPolicy,
|
||||
}
|
||||
: undefined;
|
||||
}
|
||||
|
||||
function normalizePage(page: string): string {
|
||||
// Resolve on anything that doesn't start with `/`
|
||||
if (!page.startsWith('/')) {
|
||||
@@ -499,6 +517,7 @@ export type NextImagesManifest = {
|
||||
remotePatterns: RemotePattern[];
|
||||
minimumCacheTTL?: number;
|
||||
formats?: ImageFormat[];
|
||||
unoptimized?: boolean;
|
||||
dangerouslyAllowSVG?: boolean;
|
||||
contentSecurityPolicy?: string;
|
||||
};
|
||||
@@ -2244,6 +2263,7 @@ export {
|
||||
validateEntrypoint,
|
||||
normalizePackageJson,
|
||||
getNextConfig,
|
||||
getImagesConfig,
|
||||
stringMap,
|
||||
normalizePage,
|
||||
isDynamicRoute,
|
||||
|
||||
@@ -3,6 +3,7 @@ const {
|
||||
excludeFiles,
|
||||
validateEntrypoint,
|
||||
normalizePackageJson,
|
||||
getImagesConfig,
|
||||
getNextConfig,
|
||||
} = require('../../dist/utils');
|
||||
const { FileRef } = require('@vercel/build-utils');
|
||||
@@ -27,6 +28,86 @@ describe('getNextConfig', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('getImagesConfig', () => {
|
||||
it('should return undefined when undefined config', async () => {
|
||||
const result = await getImagesConfig(undefined);
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should return undefined when null config', async () => {
|
||||
const result = await getImagesConfig(null);
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should return undefined when empty object config', async () => {
|
||||
const result = await getImagesConfig({ images: {} });
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should return pass-through props when loader is default and unoptimized undefined', async () => {
|
||||
const images = {
|
||||
loader: 'default',
|
||||
domains: ['example.com'],
|
||||
sizes: [512, 1024],
|
||||
remotePatterns: undefined,
|
||||
formats: ['image/webp'],
|
||||
minimumCacheTTL: 60,
|
||||
dangerouslyAllowSVG: false,
|
||||
contentSecurityPolicy: undefined,
|
||||
};
|
||||
const result = await getImagesConfig({ images });
|
||||
expect(result).toEqual({
|
||||
domains: ['example.com'],
|
||||
sizes: [512, 1024],
|
||||
remotePatterns: undefined,
|
||||
formats: ['image/webp'],
|
||||
minimumCacheTTL: 60,
|
||||
dangerouslyAllowSVG: false,
|
||||
contentSecurityPolicy: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it('should return pass-through props when loader is default and unoptimized false', async () => {
|
||||
const images = {
|
||||
unoptimized: false,
|
||||
loader: 'default',
|
||||
domains: ['example.com'],
|
||||
sizes: [512, 1024],
|
||||
remotePatterns: undefined,
|
||||
formats: ['image/webp'],
|
||||
minimumCacheTTL: 60,
|
||||
dangerouslyAllowSVG: false,
|
||||
contentSecurityPolicy: undefined,
|
||||
};
|
||||
const result = await getImagesConfig({ images });
|
||||
expect(result).toEqual({
|
||||
domains: ['example.com'],
|
||||
sizes: [512, 1024],
|
||||
remotePatterns: undefined,
|
||||
formats: ['image/webp'],
|
||||
minimumCacheTTL: 60,
|
||||
dangerouslyAllowSVG: false,
|
||||
contentSecurityPolicy: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it('return return undefined when loader is default and unoptimized true', async () => {
|
||||
const images = {
|
||||
unoptimized: true,
|
||||
loader: 'default',
|
||||
domains: ['example.com'],
|
||||
sizes: [512, 1024],
|
||||
remotePatterns: undefined,
|
||||
formats: ['image/webp'],
|
||||
minimumCacheTTL: 60,
|
||||
dangerouslyAllowSVG: false,
|
||||
contentSecurityPolicy: undefined,
|
||||
};
|
||||
const result = await getImagesConfig({ images });
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('excludeFiles', () => {
|
||||
it('should exclude files', () => {
|
||||
const files = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/node",
|
||||
"version": "2.8.1",
|
||||
"version": "2.8.2",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/node-js",
|
||||
@@ -31,7 +31,7 @@
|
||||
"dependencies": {
|
||||
"@edge-runtime/vm": "2.0.0",
|
||||
"@types/node": "14.18.33",
|
||||
"@vercel/build-utils": "5.7.1",
|
||||
"@vercel/build-utils": "5.7.2",
|
||||
"@vercel/node-bridge": "3.1.2",
|
||||
"@vercel/static-config": "2.0.6",
|
||||
"edge-runtime": "2.0.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/python",
|
||||
"version": "3.1.30",
|
||||
"version": "3.1.31",
|
||||
"main": "./dist/index.js",
|
||||
"license": "MIT",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/python",
|
||||
@@ -22,7 +22,7 @@
|
||||
"devDependencies": {
|
||||
"@types/execa": "^0.9.0",
|
||||
"@types/jest": "27.4.1",
|
||||
"@vercel/build-utils": "5.7.1",
|
||||
"@vercel/build-utils": "5.7.2",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"execa": "^1.0.0",
|
||||
"typescript": "4.3.4"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/redwood",
|
||||
"version": "1.0.40",
|
||||
"version": "1.0.41",
|
||||
"main": "./dist/index.js",
|
||||
"license": "MIT",
|
||||
"homepage": "https://vercel.com/docs",
|
||||
@@ -27,6 +27,6 @@
|
||||
"@types/aws-lambda": "8.10.19",
|
||||
"@types/node": "14.18.33",
|
||||
"@types/semver": "6.0.0",
|
||||
"@vercel/build-utils": "5.7.1"
|
||||
"@vercel/build-utils": "5.7.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/remix",
|
||||
"version": "1.1.2",
|
||||
"version": "1.1.3",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
"homepage": "https://vercel.com/docs",
|
||||
@@ -25,7 +25,7 @@
|
||||
"devDependencies": {
|
||||
"@types/jest": "27.5.1",
|
||||
"@types/node": "14.18.33",
|
||||
"@vercel/build-utils": "5.7.1",
|
||||
"@vercel/build-utils": "5.7.2",
|
||||
"typescript": "4.6.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@vercel/ruby",
|
||||
"author": "Nathan Cahill <nathan@nathancahill.com>",
|
||||
"version": "1.3.46",
|
||||
"version": "1.3.47",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/ruby",
|
||||
@@ -22,7 +22,7 @@
|
||||
"devDependencies": {
|
||||
"@types/fs-extra": "8.0.0",
|
||||
"@types/semver": "6.0.0",
|
||||
"@vercel/build-utils": "5.7.1",
|
||||
"@vercel/build-utils": "5.7.2",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"execa": "2.0.4",
|
||||
"fs-extra": "^7.0.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/static-build",
|
||||
"version": "1.0.43",
|
||||
"version": "1.0.44",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/build-step",
|
||||
@@ -36,8 +36,8 @@
|
||||
"@types/ms": "0.7.31",
|
||||
"@types/node-fetch": "2.5.4",
|
||||
"@types/promise-timeout": "1.3.0",
|
||||
"@vercel/build-utils": "5.7.1",
|
||||
"@vercel/frameworks": "1.1.15",
|
||||
"@vercel/build-utils": "5.7.2",
|
||||
"@vercel/frameworks": "1.1.16",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"@vercel/routing-utils": "2.1.3",
|
||||
"@vercel/static-config": "2.0.6",
|
||||
|
||||
71
yarn.lock
71
yarn.lock
@@ -2532,18 +2532,6 @@
|
||||
resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e"
|
||||
integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==
|
||||
|
||||
"@types/ansi-escapes@3.0.0":
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/ansi-escapes/-/ansi-escapes-3.0.0.tgz#619bbc6d46fc75da6d784e53b5a25d2efff07108"
|
||||
integrity sha512-aamJrX6PdmIO8E9qhZaYmXiMGXwnkF2lcga/VbqLf8g90aaKGZ4cSFP5AabqxAbmp0h69C9yE3a4fUBtVpqtmg==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/ansi-regex@4.0.0":
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/ansi-regex/-/ansi-regex-4.0.0.tgz#cb20bb66da7700ea9b26f16971f03f0e092eddad"
|
||||
integrity sha512-r1W316vjsZXn1/csLC4HcCJs6jIHIzksHJd7xx+Dl+PAb0S2Dh9cR8ZsIMEfGmbBtP7JNWlf2KKahSkDP6rg3g==
|
||||
|
||||
"@types/async-retry@1.2.1":
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/async-retry/-/async-retry-1.2.1.tgz#fa9ac165907a8ee78f4924f4e393b656c65b5bb4"
|
||||
@@ -3616,10 +3604,12 @@ ansi-align@^3.0.0:
|
||||
dependencies:
|
||||
string-width "^3.0.0"
|
||||
|
||||
ansi-escapes@3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.0.0.tgz#ec3e8b4e9f8064fc02c3ac9b65f1c275bda8ef92"
|
||||
integrity sha512-O/klc27mWNUigtv0F8NJWbLF00OcegQalkqKURWdosW08YZKi4m6CnSUSvIZG1otNJbTWhN01Hhz389DW7mvDQ==
|
||||
ansi-escapes@4.3.2:
|
||||
version "4.3.2"
|
||||
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e"
|
||||
integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==
|
||||
dependencies:
|
||||
type-fest "^0.21.3"
|
||||
|
||||
ansi-escapes@^3.0.0, ansi-escapes@^3.2.0:
|
||||
version "3.2.0"
|
||||
@@ -3633,16 +3623,21 @@ ansi-escapes@^4.2.0, ansi-escapes@^4.2.1:
|
||||
dependencies:
|
||||
type-fest "^0.11.0"
|
||||
|
||||
ansi-regex@3.0.0, ansi-regex@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
|
||||
integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
|
||||
ansi-regex@5.0.1, ansi-regex@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
|
||||
integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
|
||||
|
||||
ansi-regex@^2.0.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
|
||||
integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8=
|
||||
|
||||
ansi-regex@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
|
||||
integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
|
||||
|
||||
ansi-regex@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
|
||||
@@ -3653,11 +3648,6 @@ ansi-regex@^5.0.0:
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75"
|
||||
integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==
|
||||
|
||||
ansi-regex@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
|
||||
integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
|
||||
|
||||
ansi-styles@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
|
||||
@@ -12444,12 +12434,12 @@ stringify-object@^3.3.0:
|
||||
is-obj "^1.0.1"
|
||||
is-regexp "^1.0.0"
|
||||
|
||||
strip-ansi@5.2.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
|
||||
integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
|
||||
strip-ansi@6.0.1, strip-ansi@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||
dependencies:
|
||||
ansi-regex "^4.1.0"
|
||||
ansi-regex "^5.0.1"
|
||||
|
||||
strip-ansi@^3.0.0, strip-ansi@^3.0.1:
|
||||
version "3.0.1"
|
||||
@@ -12465,6 +12455,13 @@ strip-ansi@^4.0.0:
|
||||
dependencies:
|
||||
ansi-regex "^3.0.0"
|
||||
|
||||
strip-ansi@^5.1.0, strip-ansi@^5.2.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
|
||||
integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
|
||||
dependencies:
|
||||
ansi-regex "^4.1.0"
|
||||
|
||||
strip-ansi@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532"
|
||||
@@ -12472,13 +12469,6 @@ strip-ansi@^6.0.0:
|
||||
dependencies:
|
||||
ansi-regex "^5.0.0"
|
||||
|
||||
strip-ansi@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||
dependencies:
|
||||
ansi-regex "^5.0.1"
|
||||
|
||||
strip-bom-buf@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-bom-buf/-/strip-bom-buf-2.0.0.tgz#ff9c223937f8e7154b77e9de9bde094186885c15"
|
||||
@@ -12622,7 +12612,7 @@ supports-color@^8.0.0:
|
||||
dependencies:
|
||||
has-flag "^4.0.0"
|
||||
|
||||
supports-hyperlinks@^2.0.0:
|
||||
supports-hyperlinks@2.2.0, supports-hyperlinks@^2.0.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb"
|
||||
integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==
|
||||
@@ -13238,6 +13228,11 @@ type-fest@^0.20.2:
|
||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
|
||||
integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
|
||||
|
||||
type-fest@^0.21.3:
|
||||
version "0.21.3"
|
||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37"
|
||||
integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==
|
||||
|
||||
type-fest@^0.3.0:
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.3.1.tgz#63d00d204e059474fe5e1b7c011112bbd1dc29e1"
|
||||
|
||||
Reference in New Issue
Block a user