@netlify/plugin-nextjs 4.33.0 → 4.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -189,6 +189,7 @@ const writeEdgeFunctions = async ({ netlifyConfig, routesManifest, }) => {
189
189
  var _a;
190
190
  const manifest = {
191
191
  functions: [],
192
+ layers: [],
192
193
  version: 1,
193
194
  };
194
195
  const edgeFunctionRoot = (0, path_1.resolve)('.netlify', 'edge-functions');
@@ -291,7 +292,11 @@ const writeEdgeFunctions = async ({ netlifyConfig, routesManifest, }) => {
291
292
  manifest.functions.push({
292
293
  function: 'ipx',
293
294
  name: 'next/image handler',
294
- path: '/_next/image*',
295
+ path: nextConfig.images.path || '/_next/image',
296
+ });
297
+ manifest.layers.push({
298
+ name: 'https://ipx-edge-function-layer.netlify.app/mod.ts',
299
+ flag: 'ipx-edge-function-layer-url',
295
300
  });
296
301
  }
297
302
  else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/plugin-nextjs",
3
- "version": "4.33.0",
3
+ "version": "4.34.0",
4
4
  "description": "Run Next.js seamlessly on Netlify",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -13,7 +13,7 @@
13
13
  "dependencies": {
14
14
  "@netlify/esbuild": "0.14.39",
15
15
  "@netlify/functions": "^1.4.0",
16
- "@netlify/ipx": "^1.3.3",
16
+ "@netlify/ipx": "^1.4.0",
17
17
  "@vercel/node-bridge": "^2.1.0",
18
18
  "chalk": "^4.1.2",
19
19
  "chokidar": "^3.5.3",
@@ -37,7 +37,7 @@
37
37
  },
38
38
  "devDependencies": {
39
39
  "@delucis/if-env": "^1.1.2",
40
- "@netlify/build": "^29.7.1",
40
+ "@netlify/build": "^29.9.0",
41
41
  "@types/fs-extra": "^9.0.13",
42
42
  "@types/jest": "^27.4.1",
43
43
  "@types/merge-stream": "^1.1.2",
@@ -0,0 +1,3 @@
1
+ {
2
+ "formats": ["webp"]
3
+ }
@@ -1,73 +1,5 @@
1
- import { Accepts } from 'https://deno.land/x/accepts@2.1.1/mod.ts'
2
- import type { Context } from 'https://edge.netlify.com'
3
- // Available at build time
4
- import imageconfig from './imageconfig.json' assert { type: 'json' }
5
-
6
- const defaultFormat = 'webp'
7
-
8
- interface ImageConfig extends Record<string, unknown> {
9
- formats?: string[]
10
- }
11
-
12
- // Checks if a URL param is numeric
13
- const isNumeric = (value: string | null) => Number(value).toString() === value
14
-
15
- /**
16
- * Implement content negotiation for images
17
- */
18
-
19
- // deno-lint-ignore require-await
20
- const handler = async (req: Request, context: Context) => {
21
- const { searchParams } = new URL(req.url)
22
- const accept = new Accepts(req.headers)
23
- const { formats = [defaultFormat] } = imageconfig as ImageConfig
24
- if (formats.length === 0) {
25
- formats.push(defaultFormat)
26
- }
27
- let type = accept.types(formats) || defaultFormat
28
- if (Array.isArray(type)) {
29
- type = type[0]
30
- }
31
-
32
- const source = searchParams.get('url')
33
- const width = searchParams.get('w')
34
- const quality = searchParams.get('q') ?? '75'
1
+ import { getHandler } from 'https://ipx-edge-function-layer.netlify.app/mod.ts'
35
2
 
36
- const errors: Array<string> = []
37
-
38
- if (!source) {
39
- errors.push('Missing "url" parameter')
40
- } else if (!source.startsWith('http') && !source.startsWith('/')) {
41
- errors.push('The "url" parameter must be a valid URL or path')
42
- }
43
-
44
- if (!width) {
45
- errors.push('Missing "w" parameter')
46
- } else if (!isNumeric(width)) {
47
- errors.push('Invalid "w" parameter')
48
- }
49
-
50
- if (!isNumeric(quality)) {
51
- errors.push('Invalid "q" parameter')
52
- }
53
-
54
- if (!source || errors.length > 0) {
55
- return new Response(`Invalid request: \n${errors.join('\n')}`, {
56
- status: 400,
57
- })
58
- }
59
-
60
- const modifiers = [`w_${width}`, `q_${quality}`]
61
-
62
- if (type) {
63
- if (type.includes('/')) {
64
- // If this is a mimetype, strip "image/"
65
- type = type.split('/')[1]
66
- }
67
- modifiers.push(`f_${type}`)
68
- }
69
- const target = `/_ipx/${modifiers.join(',')}/${encodeURIComponent(source)}`
70
- return context.rewrite(target)
71
- }
3
+ import imageconfig from './imageconfig.json' assert { type: 'json' }
72
4
 
73
- export default handler
5
+ export default getHandler({ formats: imageconfig?.formats })
@@ -1,14 +1,18 @@
1
1
  import type { EdgeFunction } from 'https://edge.netlify.com'
2
2
 
3
+ // These are copied from next/dist/build. This file gets copied as part of the next
4
+ // runtime build and can't reference the next package directly.
5
+ //
6
+ // Latest types at https://github.com/vercel/next.js/blob/4a2df3c3752aeddc50fd5ab053440eccf71ae50b/packages/next/src/build/index.ts#L140
3
7
  export declare type SsgRoute = {
4
8
  initialRevalidateSeconds: number | false
5
9
  srcRoute: string | null
6
- dataRoute: string
10
+ dataRoute: string | null
7
11
  }
8
12
  export declare type DynamicSsgRoute = {
9
13
  routeRegex: string
10
14
  fallback: string | null | false
11
- dataRoute: string
15
+ dataRoute: string | null
12
16
  dataRouteRegex: string
13
17
  }
14
18
  export declare type PrerenderManifest = {
@@ -35,7 +39,7 @@ const rscifyPath = (route: string) => {
35
39
  export const getRscDataRouter = ({ routes: staticRoutes, dynamicRoutes }: PrerenderManifest): EdgeFunction => {
36
40
  const staticRouteSet = new Set(
37
41
  Object.entries(staticRoutes)
38
- .filter(([, { dataRoute }]) => dataRoute.endsWith('.rsc'))
42
+ .filter(([, { dataRoute }]) => dataRoute?.endsWith('.rsc'))
39
43
  .map(([route]) => route),
40
44
  )
41
45
 
@@ -57,10 +57,15 @@ export const addMiddlewareHeaders = async (
57
57
  return response
58
58
  }
59
59
 
60
+ interface ResponseCookies {
61
+ readonly _headers: Headers
62
+ }
63
+
60
64
  interface MiddlewareResponse extends Response {
61
65
  originResponse: Response
62
66
  dataTransforms: NextDataTransform[]
63
67
  elementHandlers: Array<[selector: string, handlers: ElementHandlers]>
68
+ get cookies(): ResponseCookies
64
69
  }
65
70
 
66
71
  interface MiddlewareRequest {
@@ -184,6 +189,12 @@ export const buildResponse = async ({
184
189
  if (request.method === 'HEAD' || request.method === 'OPTIONS') {
185
190
  return response.originResponse
186
191
  }
192
+
193
+ // NextResponse doesn't set cookies onto the originResponse, so we need to copy them over
194
+ if (response.cookies._headers.has('set-cookie')) {
195
+ response.originResponse.headers.set('set-cookie', response.cookies._headers.get('set-cookie')!)
196
+ }
197
+
187
198
  // If it's JSON we don't need to use the rewriter, we can just parse it
188
199
  if (response.originResponse.headers.get('content-type')?.includes('application/json')) {
189
200
  const props = await response.originResponse.json()