diff --git a/.github/lock.yml b/.github/lock.yml deleted file mode 100644 index c80c7a0a09968..0000000000000 --- a/.github/lock.yml +++ /dev/null @@ -1,6 +0,0 @@ -# Configuration for lock-threads - https://github.com/dessant/lock-threads - -# Number of days of inactivity before a closed issue or pull request is locked -daysUntilLock: 30 -# Comment to post before locking. Set to `false` to disable -lockComment: 'This issue has been automatically locked due to no recent activity. If you are running into a similar issue, please open a new issue with a reproduction. Thank you.' diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml new file mode 100644 index 0000000000000..c8df2516aa2c9 --- /dev/null +++ b/.github/workflows/lock.yml @@ -0,0 +1,25 @@ +name: 'Lock Threads' + +on: + schedule: + # This runs every hour: https://crontab.guru/every-1-hour + - cron: '0 * * * *' + workflow_dispatch: + +permissions: + issues: write + pull-requests: write + +concurrency: + group: lock + +jobs: + action: + runs-on: ubuntu-latest + steps: + - uses: dessant/lock-threads@v3 + with: + github-token: ${{ secrets.LOCK_TOKEN }} + issue-inactive-days: 30 + issue-comment: 'This issue has been automatically locked due to no recent activity. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.' + pr-inactive-days: 30 diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 4d15b37533f69..1cbbfceb7cc5c 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -2,7 +2,8 @@ name: 'Stale issue handler' on: workflow_dispatch: schedule: - - cron: '0 0 * * *' + # This runs every day 20 minutes before midnight: https://crontab.guru/#40_23_*_*_* + - cron: '40 23 * * *' jobs: stale: @@ -12,6 +13,7 @@ jobs: id: stale name: 'Close stale issues with no reproduction' with: + repo-token: ${{ secrets.STALE_TOKEN }} only-labels: 'please add a complete reproduction' close-issue-message: 'This issue has been automatically closed after 30 days of inactivity with no reproduction. If you are running into a similar issue, please open a new issue with a reproduction. Thank you.' days-before-issue-close: 1 @@ -19,3 +21,4 @@ jobs: days-before-pr-close: -1 days-before-pr-stale: -1 exempt-issue-labels: 'blocked,must,should,keep' + operation-per-run: 300 # 1 operation per 100 issues, the rest is to label/comment/close diff --git a/docs/basic-features/data-fetching/get-server-side-props.md b/docs/basic-features/data-fetching/get-server-side-props.md index da2f5e39aae89..22aa4d77dbf73 100644 --- a/docs/basic-features/data-fetching/get-server-side-props.md +++ b/docs/basic-features/data-fetching/get-server-side-props.md @@ -33,7 +33,7 @@ The [`getServerSideProps` API reference](/docs/api-reference/data-fetching/get-s ## When should I use getServerSideProps -You should use `getServerSideProps` only if you need to pre-render a page whose data must be fetched at request time. [Time to First Byte (TTFB)](/learn/seo/web-performance) will be higher than [`getStaticProps`](/docs/basic-features/data-fetching/get-static-props.md) because the server must compute the result on every request, and the result can only be cached by a CDN using `cache-control` headers (which could require extra configuration). +You should use `getServerSideProps` only if you need to pre-render a page whose data must be fetched at request time. [Time to First Byte (TTFB)](https://web.dev/ttfb/) will be higher than [`getStaticProps`](/docs/basic-features/data-fetching/get-static-props.md) because the server must compute the result on every request, and the result can only be cached by a CDN using `cache-control` headers (which could require extra configuration). If you do not need to pre-render the data, then you should consider fetching data on the [client side](#fetching-data-on-the-client-side). diff --git a/lerna.json b/lerna.json index b17ed878a3fb8..3fbc8625cdba1 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "12.0.9-canary.12" + "version": "12.0.9" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index 7204f3e078f19..96b77e4e77616 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "12.0.9-canary.12", + "version": "12.0.9", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index 8315f8aabadac..505f4628c3c33 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "12.0.9-canary.12", + "version": "12.0.9", "description": "ESLint configuration used by NextJS.", "main": "index.js", "license": "MIT", @@ -9,7 +9,7 @@ "directory": "packages/eslint-config-next" }, "dependencies": { - "@next/eslint-plugin-next": "12.0.9-canary.12", + "@next/eslint-plugin-next": "12.0.9", "@rushstack/eslint-patch": "^1.0.8", "@typescript-eslint/parser": "^5.0.0", "eslint-import-resolver-node": "^0.3.4", diff --git a/packages/eslint-plugin-next/package.json b/packages/eslint-plugin-next/package.json index 9405a87b6b493..d902660f367b6 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "12.0.9-canary.12", + "version": "12.0.9", "description": "ESLint plugin for NextJS.", "main": "lib/index.js", "license": "MIT", diff --git a/packages/next-bundle-analyzer/package.json b/packages/next-bundle-analyzer/package.json index 982bddb7c8c24..185a79d13f80e 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "12.0.9-canary.12", + "version": "12.0.9", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index 0cc2279928273..878fa830ed5ef 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "12.0.9-canary.12", + "version": "12.0.9", "license": "MIT", "dependencies": { "chalk": "4.1.0", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index 375d55e508fcb..5617323e10e0f 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "12.0.9-canary.12", + "version": "12.0.9", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 397d93685e047..def2ec94e6824 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "12.0.9-canary.12", + "version": "12.0.9", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 2a1cce549cfba..3b7791aa611f5 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "12.0.9-canary.12", + "version": "12.0.9", "repository": { "url": "vercel/next.js", "directory": "packages/next-plugin-storybook" diff --git a/packages/next-polyfill-module/package.json b/packages/next-polyfill-module/package.json index 4760c3bf9871e..b1bf84d56f61e 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "12.0.9-canary.12", + "version": "12.0.9", "description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)", "main": "dist/polyfill-module.js", "license": "MIT", diff --git a/packages/next-polyfill-nomodule/package.json b/packages/next-polyfill-nomodule/package.json index ea1a5bf15c5d9..1f3736c96b786 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "12.0.9-canary.12", + "version": "12.0.9", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index b397a17eeb02b..be84cbfa3e27b 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "12.0.9-canary.12", + "version": "12.0.9", "private": true, "scripts": { "build-native": "napi build --platform --cargo-name next_swc_napi native", diff --git a/packages/next/package.json b/packages/next/package.json index d66936dad338f..acd0260841b02 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "12.0.9-canary.12", + "version": "12.0.9", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -71,7 +71,7 @@ ] }, "dependencies": { - "@next/env": "12.0.9-canary.12", + "@next/env": "12.0.9", "caniuse-lite": "^1.0.30001283", "postcss": "8.4.5", "styled-jsx": "5.0.0", @@ -119,11 +119,11 @@ "@hapi/accept": "5.0.2", "@napi-rs/cli": "1.2.1", "@napi-rs/triples": "1.0.3", - "@next/polyfill-module": "12.0.9-canary.12", - "@next/polyfill-nomodule": "12.0.9-canary.12", - "@next/react-dev-overlay": "12.0.9-canary.12", - "@next/react-refresh-utils": "12.0.9-canary.12", - "@next/swc": "12.0.9-canary.12", + "@next/polyfill-module": "12.0.9", + "@next/polyfill-nomodule": "12.0.9", + "@next/react-dev-overlay": "12.0.9", + "@next/react-refresh-utils": "12.0.9", + "@next/swc": "12.0.9", "@peculiar/webcrypto": "1.1.7", "@taskr/clear": "1.1.0", "@taskr/esnext": "1.1.0", diff --git a/packages/next/server/image-optimizer.ts b/packages/next/server/image-optimizer.ts index de5a631573130..7a0f7fe1ec180 100644 --- a/packages/next/server/image-optimizer.ts +++ b/packages/next/server/image-optimizer.ts @@ -253,8 +253,17 @@ export async function imageOptimizer( mockRes.write = (chunk: Buffer | string) => { resBuffers.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)) } - mockRes._write = (chunk: Buffer | string) => { + mockRes._write = ( + chunk: Buffer | string, + _encoding: string, + callback: () => void + ) => { mockRes.write(chunk) + // According to Node.js documentation, the callback MUST be invoked to signal that + // the write completed successfully. If this callback is not invoked, the 'finish' event + // will not be emitted. + // https://nodejs.org/docs/latest-v16.x/api/stream.html#writable_writechunk-encoding-callback + callback() } const mockHeaders: Record = {} @@ -290,7 +299,6 @@ export async function imageOptimizer( await handleRequest(mockReq, mockRes, nodeUrl.parse(href, true)) await isStreamFinished res.statusCode = mockRes.statusCode - upstreamBuffer = Buffer.concat(resBuffers) upstreamType = detectContentType(upstreamBuffer) || mockRes.getHeader('Content-Type') @@ -328,7 +336,6 @@ export async function imageOptimizer( ) return { finished: true } } - if (!upstreamType.startsWith('image/')) { res.statusCode = 400 res.end("The requested resource isn't a valid image.") diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index 8cda508cce57a..a8a7000224e7f 100644 --- a/packages/react-dev-overlay/package.json +++ b/packages/react-dev-overlay/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-dev-overlay", - "version": "12.0.9-canary.12", + "version": "12.0.9", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index 8ea294f3ba9e8..66c4a46dcbd41 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "12.0.9-canary.12", + "version": "12.0.9", "description": "An experimental package providing utilities for React Refresh.", "repository": { "url": "vercel/next.js", diff --git a/test/integration/image-optimizer/test/index.test.js b/test/integration/image-optimizer/test/index.test.js index 89f9cd36d7fff..26ea2bfc9d3a4 100644 --- a/test/integration/image-optimizer/test/index.test.js +++ b/test/integration/image-optimizer/test/index.test.js @@ -779,6 +779,14 @@ function runTests({ expect(await res.text()).toBe("The requested resource isn't a valid image.") }) + it('should error if the image file does not exist', async () => { + const query = { url: '/does_not_exist.jpg', w, q: 80 } + const opts = { headers: { accept: 'image/webp' } } + const res = await fetchViaHTTP(appPort, '/_next/image', query, opts) + expect(res.status).toBe(400) + expect(await res.text()).toBe("The requested resource isn't a valid image.") + }) + it('should handle concurrent requests', async () => { await fs.remove(imagesDir) const query = { url: '/test.png', w, q: 80 }